bunkit-cli 0.6.1 → 0.8.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 (3) hide show
  1. package/README.md +61 -3
  2. package/dist/index.js +2177 -160
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3773,22 +3773,23 @@ var quotes, getRandomQuote = () => {
3773
3773
  `, createBanner = (version = "0.3.1") => {
3774
3774
  const quote = getRandomQuote();
3775
3775
  const content = [
3776
- source_default.yellow(logo.trim()),
3776
+ source_default.yellowBright(logo.trim()),
3777
3777
  "",
3778
- source_default.cyan("\uD83C\uDF5E Bake production-ready apps in seconds"),
3779
- source_default.dim("Modern \u2022 Fast \u2022 Opinionated"),
3778
+ source_default.bold.cyan("\uD83C\uDF5E Bake production-ready apps in seconds"),
3779
+ source_default.dim("Modern \u2022 Fast \u2022 Opinionated \u2022 Type-Safe"),
3780
3780
  "",
3781
- source_default.cyan(quote),
3781
+ source_default.italic.cyan(quote),
3782
3782
  "",
3783
- source_default.dim(`v${version}`)
3783
+ source_default.dim(`Version ${version}`)
3784
3784
  ].join(`
3785
3785
  `);
3786
3786
  return boxen(content, {
3787
- padding: 1,
3787
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
3788
3788
  margin: { top: 1, bottom: 1 },
3789
- borderColor: "gray",
3789
+ borderColor: "cyan",
3790
3790
  borderStyle: "round",
3791
- dimBorder: true
3791
+ title: "bunkit",
3792
+ titleAlignment: "center"
3792
3793
  });
3793
3794
  }, showBanner = (version) => {
3794
3795
  console.log(createBanner(version));
@@ -22651,11 +22652,17 @@ var init_types2 = __esm(() => {
22651
22652
  features: exports_external.array(exports_external.string()).optional(),
22652
22653
  git: exports_external.boolean().default(true),
22653
22654
  install: exports_external.boolean().default(true),
22654
- database: exports_external.enum(["postgres-drizzle", "supabase", "sqlite-drizzle", "none"]).optional(),
22655
+ database: exports_external.enum(["postgres-drizzle", "supabase", "supabase-drizzle", "sqlite-drizzle", "none"]).optional(),
22656
+ supabasePreset: exports_external.enum(["full-stack", "auth-only", "database-only", "custom"]).optional(),
22657
+ supabaseFeatures: exports_external.array(exports_external.enum(["auth", "storage", "realtime", "edge-functions", "database"])).optional(),
22658
+ supabaseWithDrizzle: exports_external.boolean().optional(),
22655
22659
  codeQuality: exports_external.enum(["ultracite", "biome"]).default("ultracite"),
22656
22660
  tsStrictness: exports_external.enum(["strict", "moderate", "loose"]).default("strict"),
22657
22661
  uiLibrary: exports_external.enum(["shadcn", "none"]).optional(),
22658
22662
  cssFramework: exports_external.enum(["tailwind", "vanilla", "css-modules"]).optional(),
22663
+ shadcnStyle: exports_external.enum(["new-york", "default"]).optional(),
22664
+ shadcnBaseColor: exports_external.enum(["neutral", "gray", "zinc", "stone", "slate"]).optional(),
22665
+ shadcnRadius: exports_external.string().optional(),
22659
22666
  testing: exports_external.enum(["bun-test", "vitest", "none"]).default("bun-test"),
22660
22667
  docker: exports_external.boolean().default(false),
22661
22668
  cicd: exports_external.boolean().default(false),
@@ -22807,7 +22814,13 @@ function createTemplateContext(config) {
22807
22814
  docker: config.docker,
22808
22815
  cicd: config.cicd,
22809
22816
  envExample: config.envExample,
22810
- pathAliases: config.pathAliases
22817
+ pathAliases: config.pathAliases,
22818
+ shadcnStyle: config.shadcnStyle,
22819
+ shadcnBaseColor: config.shadcnBaseColor,
22820
+ shadcnRadius: config.shadcnRadius,
22821
+ supabasePreset: config.supabasePreset,
22822
+ supabaseFeatures: config.supabaseFeatures,
22823
+ supabaseWithDrizzle: config.supabaseWithDrizzle
22811
22824
  };
22812
22825
  }
22813
22826
  var import_fs_extra2;
@@ -24182,6 +24195,41 @@ class dD extends x {
24182
24195
  }
24183
24196
  var A;
24184
24197
  A = new WeakMap;
24198
+ var kD = Object.defineProperty;
24199
+ var $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
24200
+ var H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t);
24201
+ var SD = class extends x {
24202
+ constructor(u) {
24203
+ super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
24204
+ t === "a" && this.toggleAll();
24205
+ }), this.on("cursor", (t) => {
24206
+ switch (t) {
24207
+ case "left":
24208
+ case "up":
24209
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
24210
+ break;
24211
+ case "down":
24212
+ case "right":
24213
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
24214
+ break;
24215
+ case "space":
24216
+ this.toggleValue();
24217
+ break;
24218
+ }
24219
+ });
24220
+ }
24221
+ get _value() {
24222
+ return this.options[this.cursor].value;
24223
+ }
24224
+ toggleAll() {
24225
+ const u = this.value.length === this.options.length;
24226
+ this.value = u ? [] : this.options.map((t) => t.value);
24227
+ }
24228
+ toggleValue() {
24229
+ const u = this.value.includes(this._value);
24230
+ this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
24231
+ }
24232
+ };
24185
24233
  var OD = Object.defineProperty;
24186
24234
  var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
24187
24235
  var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
@@ -24353,6 +24401,47 @@ ${import_picocolors2.default.cyan(d2)}
24353
24401
  }
24354
24402
  } }).prompt();
24355
24403
  };
24404
+ var fe = (t) => {
24405
+ const n = (r2, i) => {
24406
+ const s = r2.label ?? String(r2.value);
24407
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
24408
+ };
24409
+ return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
24410
+ if (this.required && r2.length === 0)
24411
+ return `Please select at least one option.
24412
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
24413
+ }, render() {
24414
+ const r2 = `${import_picocolors2.default.gray(o)}
24415
+ ${b2(this.state)} ${t.message}
24416
+ `, i = (s, c) => {
24417
+ const a = this.value.includes(s.value);
24418
+ return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
24419
+ };
24420
+ switch (this.state) {
24421
+ case "submit":
24422
+ return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
24423
+ case "cancel": {
24424
+ const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
24425
+ return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
24426
+ ${import_picocolors2.default.gray(o)}` : ""}`;
24427
+ }
24428
+ case "error": {
24429
+ const s = this.error.split(`
24430
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
24431
+ `);
24432
+ return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
24433
+ ${import_picocolors2.default.yellow(o)} `)}
24434
+ ${s}
24435
+ `;
24436
+ }
24437
+ default:
24438
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
24439
+ ${import_picocolors2.default.cyan(o)} `)}
24440
+ ${import_picocolors2.default.cyan(d2)}
24441
+ `;
24442
+ }
24443
+ } }).prompt();
24444
+ };
24356
24445
  var Me = (t = "", n = "") => {
24357
24446
  const r2 = `
24358
24447
  ${t}
@@ -24424,7 +24513,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
24424
24513
  }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
24425
24514
  const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
24426
24515
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
24427
- }, H = (m2 = "") => {
24516
+ }, H2 = (m2 = "") => {
24428
24517
  a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
24429
24518
  `);
24430
24519
  let h2 = 0, w2 = 0;
@@ -24450,21 +24539,20 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
24450
24539
  `) : process.stdout.write(`${w2} ${l2}
24451
24540
  `), E(), s();
24452
24541
  };
24453
- return { start: H, stop: N2, message: (m2 = "") => {
24542
+ return { start: H2, stop: N2, message: (m2 = "") => {
24454
24543
  l2 = R2(m2 ?? l2);
24455
24544
  } };
24456
24545
  };
24457
24546
 
24458
24547
  // src/index.ts
24459
24548
  init_src();
24460
- var import_picocolors7 = __toESM(require_picocolors(), 1);
24549
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
24461
24550
 
24462
24551
  // src/commands/init.enhanced.ts
24463
24552
  init_boxen();
24464
24553
  init_source();
24465
24554
  init_dist();
24466
24555
  init_src();
24467
- var import_picocolors4 = __toESM(require_picocolors(), 1);
24468
24556
 
24469
24557
  // ../templates/src/render.ts
24470
24558
  var import_ejs = __toESM(require_ejs(), 1);
@@ -24827,12 +24915,12 @@ services:
24827
24915
  - "3000:3000"
24828
24916
  environment:
24829
24917
  - NODE_ENV=production
24830
- ${context.database && context.database !== "none" && context.database !== "supabase" ? "- DATABASE_URL=${DATABASE_URL:-postgres://postgres:postgres@db:5432/${context.projectName}}" : ""}
24831
- ${context.database && context.database !== "none" && context.database !== "supabase" ? `depends_on:
24918
+ ${context.database && context.database !== "none" && context.database !== "supabase" && context.database !== "supabase-drizzle" ? "- DATABASE_URL=${DATABASE_URL:-postgres://postgres:postgres@db:5432/${context.projectName}}" : ""}
24919
+ ${context.database && context.database !== "none" && context.database !== "supabase" && context.database !== "supabase-drizzle" ? `depends_on:
24832
24920
  - db` : ""}
24833
24921
  restart: unless-stopped
24834
24922
 
24835
- ${context.database && context.database !== "none" && context.database !== "supabase" ? `db:
24923
+ ${context.database && context.database !== "none" && context.database !== "supabase" && context.database !== "supabase-drizzle" ? `db:
24836
24924
  image: ${context.database === "sqlite-drizzle" ? "alpine:latest" : "postgres:16-alpine"}
24837
24925
  ${context.database !== "sqlite-drizzle" ? `environment:
24838
24926
  - POSTGRES_USER=postgres
@@ -24987,7 +25075,7 @@ jobs:
24987
25075
  ${context.preset === "web" || context.preset === "full" ? `- name: Build application
24988
25076
  run: bun run build
24989
25077
  env:
24990
- ${context.database === "supabase" ? `NEXT_PUBLIC_SUPABASE_URL: \${{ secrets.SUPABASE_URL }}
25078
+ ${context.database === "supabase" || context.database === "supabase-drizzle" ? `NEXT_PUBLIC_SUPABASE_URL: \${{ secrets.SUPABASE_URL }}
24991
25079
  NEXT_PUBLIC_SUPABASE_ANON_KEY: \${{ secrets.SUPABASE_ANON_KEY }}
24992
25080
  ` : ""}NODE_ENV: production` : ""}
24993
25081
 
@@ -25074,6 +25162,1183 @@ updates:
25074
25162
  await writeFile(join(projectPath, ".github/dependabot.yml"), dependabotConfig);
25075
25163
  }
25076
25164
 
25165
+ // ../templates/src/generators/shadcn.ts
25166
+ init_dist();
25167
+ init_src();
25168
+
25169
+ // ../templates/src/generators/shadcn-themes.ts
25170
+ var neutralTheme = {
25171
+ light: {
25172
+ radius: "0.625rem",
25173
+ background: "oklch(1 0 0)",
25174
+ foreground: "oklch(0.145 0 0)",
25175
+ card: "oklch(1 0 0)",
25176
+ cardForeground: "oklch(0.145 0 0)",
25177
+ popover: "oklch(1 0 0)",
25178
+ popoverForeground: "oklch(0.145 0 0)",
25179
+ primary: "oklch(0.205 0 0)",
25180
+ primaryForeground: "oklch(0.985 0 0)",
25181
+ secondary: "oklch(0.97 0 0)",
25182
+ secondaryForeground: "oklch(0.205 0 0)",
25183
+ muted: "oklch(0.97 0 0)",
25184
+ mutedForeground: "oklch(0.556 0 0)",
25185
+ accent: "oklch(0.97 0 0)",
25186
+ accentForeground: "oklch(0.205 0 0)",
25187
+ destructive: "oklch(0.577 0.245 27.325)",
25188
+ destructiveForeground: "oklch(0.577 0.245 27.325)",
25189
+ border: "oklch(0.922 0 0)",
25190
+ input: "oklch(0.922 0 0)",
25191
+ ring: "oklch(0.708 0 0)",
25192
+ chart1: "oklch(0.646 0.222 41.116)",
25193
+ chart2: "oklch(0.6 0.118 184.704)",
25194
+ chart3: "oklch(0.398 0.07 227.392)",
25195
+ chart4: "oklch(0.828 0.189 84.429)",
25196
+ chart5: "oklch(0.769 0.188 70.08)",
25197
+ sidebar: "oklch(0.985 0 0)",
25198
+ sidebarForeground: "oklch(0.145 0 0)",
25199
+ sidebarPrimary: "oklch(0.205 0 0)",
25200
+ sidebarPrimaryForeground: "oklch(0.985 0 0)",
25201
+ sidebarAccent: "oklch(0.97 0 0)",
25202
+ sidebarAccentForeground: "oklch(0.205 0 0)",
25203
+ sidebarBorder: "oklch(0.922 0 0)",
25204
+ sidebarRing: "oklch(0.708 0 0)"
25205
+ },
25206
+ dark: {
25207
+ background: "oklch(0.145 0 0)",
25208
+ foreground: "oklch(0.985 0 0)",
25209
+ card: "oklch(0.145 0 0)",
25210
+ cardForeground: "oklch(0.985 0 0)",
25211
+ popover: "oklch(0.145 0 0)",
25212
+ popoverForeground: "oklch(0.985 0 0)",
25213
+ primary: "oklch(0.985 0 0)",
25214
+ primaryForeground: "oklch(0.205 0 0)",
25215
+ secondary: "oklch(0.269 0 0)",
25216
+ secondaryForeground: "oklch(0.985 0 0)",
25217
+ muted: "oklch(0.269 0 0)",
25218
+ mutedForeground: "oklch(0.708 0 0)",
25219
+ accent: "oklch(0.269 0 0)",
25220
+ accentForeground: "oklch(0.985 0 0)",
25221
+ destructive: "oklch(0.396 0.141 25.723)",
25222
+ destructiveForeground: "oklch(0.637 0.237 25.331)",
25223
+ border: "oklch(0.269 0 0)",
25224
+ input: "oklch(0.269 0 0)",
25225
+ ring: "oklch(0.439 0 0)",
25226
+ chart1: "oklch(0.488 0.243 264.376)",
25227
+ chart2: "oklch(0.696 0.17 162.48)",
25228
+ chart3: "oklch(0.769 0.188 70.08)",
25229
+ chart4: "oklch(0.627 0.265 303.9)",
25230
+ chart5: "oklch(0.645 0.246 16.439)",
25231
+ sidebar: "oklch(0.205 0 0)",
25232
+ sidebarForeground: "oklch(0.985 0 0)",
25233
+ sidebarPrimary: "oklch(0.488 0.243 264.376)",
25234
+ sidebarPrimaryForeground: "oklch(0.985 0 0)",
25235
+ sidebarAccent: "oklch(0.269 0 0)",
25236
+ sidebarAccentForeground: "oklch(0.985 0 0)",
25237
+ sidebarBorder: "oklch(0.269 0 0)",
25238
+ sidebarRing: "oklch(0.439 0 0)"
25239
+ }
25240
+ };
25241
+ var grayTheme = {
25242
+ light: {
25243
+ radius: "0.625rem",
25244
+ background: "oklch(1 0 0)",
25245
+ foreground: "oklch(0.13 0.028 261.692)",
25246
+ card: "oklch(1 0 0)",
25247
+ cardForeground: "oklch(0.13 0.028 261.692)",
25248
+ popover: "oklch(1 0 0)",
25249
+ popoverForeground: "oklch(0.13 0.028 261.692)",
25250
+ primary: "oklch(0.21 0.034 264.665)",
25251
+ primaryForeground: "oklch(0.985 0.002 247.839)",
25252
+ secondary: "oklch(0.967 0.003 264.542)",
25253
+ secondaryForeground: "oklch(0.21 0.034 264.665)",
25254
+ muted: "oklch(0.967 0.003 264.542)",
25255
+ mutedForeground: "oklch(0.551 0.027 264.364)",
25256
+ accent: "oklch(0.967 0.003 264.542)",
25257
+ accentForeground: "oklch(0.21 0.034 264.665)",
25258
+ destructive: "oklch(0.577 0.245 27.325)",
25259
+ destructiveForeground: "oklch(0.577 0.245 27.325)",
25260
+ border: "oklch(0.928 0.006 264.531)",
25261
+ input: "oklch(0.928 0.006 264.531)",
25262
+ ring: "oklch(0.707 0.022 261.325)",
25263
+ chart1: "oklch(0.646 0.222 41.116)",
25264
+ chart2: "oklch(0.6 0.118 184.704)",
25265
+ chart3: "oklch(0.398 0.07 227.392)",
25266
+ chart4: "oklch(0.828 0.189 84.429)",
25267
+ chart5: "oklch(0.769 0.188 70.08)",
25268
+ sidebar: "oklch(0.985 0.002 247.839)",
25269
+ sidebarForeground: "oklch(0.13 0.028 261.692)",
25270
+ sidebarPrimary: "oklch(0.21 0.034 264.665)",
25271
+ sidebarPrimaryForeground: "oklch(0.985 0.002 247.839)",
25272
+ sidebarAccent: "oklch(0.967 0.003 264.542)",
25273
+ sidebarAccentForeground: "oklch(0.21 0.034 264.665)",
25274
+ sidebarBorder: "oklch(0.928 0.006 264.531)",
25275
+ sidebarRing: "oklch(0.707 0.022 261.325)"
25276
+ },
25277
+ dark: {
25278
+ background: "oklch(0.13 0.028 261.692)",
25279
+ foreground: "oklch(0.985 0.002 247.839)",
25280
+ card: "oklch(0.21 0.034 264.665)",
25281
+ cardForeground: "oklch(0.985 0.002 247.839)",
25282
+ popover: "oklch(0.21 0.034 264.665)",
25283
+ popoverForeground: "oklch(0.985 0.002 247.839)",
25284
+ primary: "oklch(0.928 0.006 264.531)",
25285
+ primaryForeground: "oklch(0.21 0.034 264.665)",
25286
+ secondary: "oklch(0.278 0.033 256.848)",
25287
+ secondaryForeground: "oklch(0.985 0.002 247.839)",
25288
+ muted: "oklch(0.278 0.033 256.848)",
25289
+ mutedForeground: "oklch(0.707 0.022 261.325)",
25290
+ accent: "oklch(0.278 0.033 256.848)",
25291
+ accentForeground: "oklch(0.985 0.002 247.839)",
25292
+ destructive: "oklch(0.704 0.191 22.216)",
25293
+ destructiveForeground: "oklch(0.704 0.191 22.216)",
25294
+ border: "oklch(1 0 0 / 10%)",
25295
+ input: "oklch(1 0 0 / 15%)",
25296
+ ring: "oklch(0.551 0.027 264.364)",
25297
+ chart1: "oklch(0.488 0.243 264.376)",
25298
+ chart2: "oklch(0.696 0.17 162.48)",
25299
+ chart3: "oklch(0.769 0.188 70.08)",
25300
+ chart4: "oklch(0.627 0.265 303.9)",
25301
+ chart5: "oklch(0.645 0.246 16.439)",
25302
+ sidebar: "oklch(0.21 0.034 264.665)",
25303
+ sidebarForeground: "oklch(0.985 0.002 247.839)",
25304
+ sidebarPrimary: "oklch(0.488 0.243 264.376)",
25305
+ sidebarPrimaryForeground: "oklch(0.985 0.002 247.839)",
25306
+ sidebarAccent: "oklch(0.278 0.033 256.848)",
25307
+ sidebarAccentForeground: "oklch(0.985 0.002 247.839)",
25308
+ sidebarBorder: "oklch(1 0 0 / 10%)",
25309
+ sidebarRing: "oklch(0.551 0.027 264.364)"
25310
+ }
25311
+ };
25312
+ var zincTheme = {
25313
+ light: {
25314
+ radius: "0.625rem",
25315
+ background: "oklch(1 0 0)",
25316
+ foreground: "oklch(0.141 0.005 285.823)",
25317
+ card: "oklch(1 0 0)",
25318
+ cardForeground: "oklch(0.141 0.005 285.823)",
25319
+ popover: "oklch(1 0 0)",
25320
+ popoverForeground: "oklch(0.141 0.005 285.823)",
25321
+ primary: "oklch(0.21 0.006 285.885)",
25322
+ primaryForeground: "oklch(0.985 0 0)",
25323
+ secondary: "oklch(0.967 0.001 286.375)",
25324
+ secondaryForeground: "oklch(0.21 0.006 285.885)",
25325
+ muted: "oklch(0.967 0.001 286.375)",
25326
+ mutedForeground: "oklch(0.552 0.016 285.938)",
25327
+ accent: "oklch(0.967 0.001 286.375)",
25328
+ accentForeground: "oklch(0.21 0.006 285.885)",
25329
+ destructive: "oklch(0.577 0.245 27.325)",
25330
+ destructiveForeground: "oklch(0.577 0.245 27.325)",
25331
+ border: "oklch(0.92 0.004 286.32)",
25332
+ input: "oklch(0.92 0.004 286.32)",
25333
+ ring: "oklch(0.705 0.015 286.067)",
25334
+ chart1: "oklch(0.646 0.222 41.116)",
25335
+ chart2: "oklch(0.6 0.118 184.704)",
25336
+ chart3: "oklch(0.398 0.07 227.392)",
25337
+ chart4: "oklch(0.828 0.189 84.429)",
25338
+ chart5: "oklch(0.769 0.188 70.08)",
25339
+ sidebar: "oklch(0.985 0 0)",
25340
+ sidebarForeground: "oklch(0.141 0.005 285.823)",
25341
+ sidebarPrimary: "oklch(0.21 0.006 285.885)",
25342
+ sidebarPrimaryForeground: "oklch(0.985 0 0)",
25343
+ sidebarAccent: "oklch(0.967 0.001 286.375)",
25344
+ sidebarAccentForeground: "oklch(0.21 0.006 285.885)",
25345
+ sidebarBorder: "oklch(0.92 0.004 286.32)",
25346
+ sidebarRing: "oklch(0.705 0.015 286.067)"
25347
+ },
25348
+ dark: {
25349
+ background: "oklch(0.141 0.005 285.823)",
25350
+ foreground: "oklch(0.985 0 0)",
25351
+ card: "oklch(0.21 0.006 285.885)",
25352
+ cardForeground: "oklch(0.985 0 0)",
25353
+ popover: "oklch(0.21 0.006 285.885)",
25354
+ popoverForeground: "oklch(0.985 0 0)",
25355
+ primary: "oklch(0.92 0.004 286.32)",
25356
+ primaryForeground: "oklch(0.21 0.006 285.885)",
25357
+ secondary: "oklch(0.274 0.006 286.033)",
25358
+ secondaryForeground: "oklch(0.985 0 0)",
25359
+ muted: "oklch(0.274 0.006 286.033)",
25360
+ mutedForeground: "oklch(0.705 0.015 286.067)",
25361
+ accent: "oklch(0.274 0.006 286.033)",
25362
+ accentForeground: "oklch(0.985 0 0)",
25363
+ destructive: "oklch(0.704 0.191 22.216)",
25364
+ destructiveForeground: "oklch(0.704 0.191 22.216)",
25365
+ border: "oklch(1 0 0 / 10%)",
25366
+ input: "oklch(1 0 0 / 15%)",
25367
+ ring: "oklch(0.552 0.016 285.938)",
25368
+ chart1: "oklch(0.488 0.243 264.376)",
25369
+ chart2: "oklch(0.696 0.17 162.48)",
25370
+ chart3: "oklch(0.769 0.188 70.08)",
25371
+ chart4: "oklch(0.627 0.265 303.9)",
25372
+ chart5: "oklch(0.645 0.246 16.439)",
25373
+ sidebar: "oklch(0.21 0.006 285.885)",
25374
+ sidebarForeground: "oklch(0.985 0 0)",
25375
+ sidebarPrimary: "oklch(0.488 0.243 264.376)",
25376
+ sidebarPrimaryForeground: "oklch(0.985 0 0)",
25377
+ sidebarAccent: "oklch(0.274 0.006 286.033)",
25378
+ sidebarAccentForeground: "oklch(0.985 0 0)",
25379
+ sidebarBorder: "oklch(1 0 0 / 10%)",
25380
+ sidebarRing: "oklch(0.552 0.016 285.938)"
25381
+ }
25382
+ };
25383
+ var stoneTheme = {
25384
+ light: {
25385
+ radius: "0.625rem",
25386
+ background: "oklch(1 0 0)",
25387
+ foreground: "oklch(0.147 0.004 49.25)",
25388
+ card: "oklch(1 0 0)",
25389
+ cardForeground: "oklch(0.147 0.004 49.25)",
25390
+ popover: "oklch(1 0 0)",
25391
+ popoverForeground: "oklch(0.147 0.004 49.25)",
25392
+ primary: "oklch(0.216 0.006 56.043)",
25393
+ primaryForeground: "oklch(0.985 0.001 106.423)",
25394
+ secondary: "oklch(0.97 0.001 106.424)",
25395
+ secondaryForeground: "oklch(0.216 0.006 56.043)",
25396
+ muted: "oklch(0.97 0.001 106.424)",
25397
+ mutedForeground: "oklch(0.553 0.013 58.071)",
25398
+ accent: "oklch(0.97 0.001 106.424)",
25399
+ accentForeground: "oklch(0.216 0.006 56.043)",
25400
+ destructive: "oklch(0.577 0.245 27.325)",
25401
+ destructiveForeground: "oklch(0.577 0.245 27.325)",
25402
+ border: "oklch(0.923 0.003 48.717)",
25403
+ input: "oklch(0.923 0.003 48.717)",
25404
+ ring: "oklch(0.709 0.01 56.259)",
25405
+ chart1: "oklch(0.646 0.222 41.116)",
25406
+ chart2: "oklch(0.6 0.118 184.704)",
25407
+ chart3: "oklch(0.398 0.07 227.392)",
25408
+ chart4: "oklch(0.828 0.189 84.429)",
25409
+ chart5: "oklch(0.769 0.188 70.08)",
25410
+ sidebar: "oklch(0.985 0.001 106.423)",
25411
+ sidebarForeground: "oklch(0.147 0.004 49.25)",
25412
+ sidebarPrimary: "oklch(0.216 0.006 56.043)",
25413
+ sidebarPrimaryForeground: "oklch(0.985 0.001 106.423)",
25414
+ sidebarAccent: "oklch(0.97 0.001 106.424)",
25415
+ sidebarAccentForeground: "oklch(0.216 0.006 56.043)",
25416
+ sidebarBorder: "oklch(0.923 0.003 48.717)",
25417
+ sidebarRing: "oklch(0.709 0.01 56.259)"
25418
+ },
25419
+ dark: {
25420
+ background: "oklch(0.147 0.004 49.25)",
25421
+ foreground: "oklch(0.985 0.001 106.423)",
25422
+ card: "oklch(0.216 0.006 56.043)",
25423
+ cardForeground: "oklch(0.985 0.001 106.423)",
25424
+ popover: "oklch(0.216 0.006 56.043)",
25425
+ popoverForeground: "oklch(0.985 0.001 106.423)",
25426
+ primary: "oklch(0.923 0.003 48.717)",
25427
+ primaryForeground: "oklch(0.216 0.006 56.043)",
25428
+ secondary: "oklch(0.268 0.007 34.298)",
25429
+ secondaryForeground: "oklch(0.985 0.001 106.423)",
25430
+ muted: "oklch(0.268 0.007 34.298)",
25431
+ mutedForeground: "oklch(0.709 0.01 56.259)",
25432
+ accent: "oklch(0.268 0.007 34.298)",
25433
+ accentForeground: "oklch(0.985 0.001 106.423)",
25434
+ destructive: "oklch(0.704 0.191 22.216)",
25435
+ destructiveForeground: "oklch(0.704 0.191 22.216)",
25436
+ border: "oklch(1 0 0 / 10%)",
25437
+ input: "oklch(1 0 0 / 15%)",
25438
+ ring: "oklch(0.553 0.013 58.071)",
25439
+ chart1: "oklch(0.488 0.243 264.376)",
25440
+ chart2: "oklch(0.696 0.17 162.48)",
25441
+ chart3: "oklch(0.769 0.188 70.08)",
25442
+ chart4: "oklch(0.627 0.265 303.9)",
25443
+ chart5: "oklch(0.645 0.246 16.439)",
25444
+ sidebar: "oklch(0.216 0.006 56.043)",
25445
+ sidebarForeground: "oklch(0.985 0.001 106.423)",
25446
+ sidebarPrimary: "oklch(0.488 0.243 264.376)",
25447
+ sidebarPrimaryForeground: "oklch(0.985 0.001 106.423)",
25448
+ sidebarAccent: "oklch(0.268 0.007 34.298)",
25449
+ sidebarAccentForeground: "oklch(0.985 0.001 106.423)",
25450
+ sidebarBorder: "oklch(1 0 0 / 10%)",
25451
+ sidebarRing: "oklch(0.553 0.013 58.071)"
25452
+ }
25453
+ };
25454
+ var slateTheme = {
25455
+ light: {
25456
+ radius: "0.625rem",
25457
+ background: "oklch(1 0 0)",
25458
+ foreground: "oklch(0.129 0.042 264.695)",
25459
+ card: "oklch(1 0 0)",
25460
+ cardForeground: "oklch(0.129 0.042 264.695)",
25461
+ popover: "oklch(1 0 0)",
25462
+ popoverForeground: "oklch(0.129 0.042 264.695)",
25463
+ primary: "oklch(0.208 0.042 265.755)",
25464
+ primaryForeground: "oklch(0.984 0.003 247.858)",
25465
+ secondary: "oklch(0.968 0.007 247.896)",
25466
+ secondaryForeground: "oklch(0.208 0.042 265.755)",
25467
+ muted: "oklch(0.968 0.007 247.896)",
25468
+ mutedForeground: "oklch(0.554 0.046 257.417)",
25469
+ accent: "oklch(0.968 0.007 247.896)",
25470
+ accentForeground: "oklch(0.208 0.042 265.755)",
25471
+ destructive: "oklch(0.577 0.245 27.325)",
25472
+ destructiveForeground: "oklch(0.577 0.245 27.325)",
25473
+ border: "oklch(0.929 0.013 255.508)",
25474
+ input: "oklch(0.929 0.013 255.508)",
25475
+ ring: "oklch(0.704 0.04 256.788)",
25476
+ chart1: "oklch(0.646 0.222 41.116)",
25477
+ chart2: "oklch(0.6 0.118 184.704)",
25478
+ chart3: "oklch(0.398 0.07 227.392)",
25479
+ chart4: "oklch(0.828 0.189 84.429)",
25480
+ chart5: "oklch(0.769 0.188 70.08)",
25481
+ sidebar: "oklch(0.984 0.003 247.858)",
25482
+ sidebarForeground: "oklch(0.129 0.042 264.695)",
25483
+ sidebarPrimary: "oklch(0.208 0.042 265.755)",
25484
+ sidebarPrimaryForeground: "oklch(0.984 0.003 247.858)",
25485
+ sidebarAccent: "oklch(0.968 0.007 247.896)",
25486
+ sidebarAccentForeground: "oklch(0.208 0.042 265.755)",
25487
+ sidebarBorder: "oklch(0.929 0.013 255.508)",
25488
+ sidebarRing: "oklch(0.704 0.04 256.788)"
25489
+ },
25490
+ dark: {
25491
+ background: "oklch(0.129 0.042 264.695)",
25492
+ foreground: "oklch(0.984 0.003 247.858)",
25493
+ card: "oklch(0.208 0.042 265.755)",
25494
+ cardForeground: "oklch(0.984 0.003 247.858)",
25495
+ popover: "oklch(0.208 0.042 265.755)",
25496
+ popoverForeground: "oklch(0.984 0.003 247.858)",
25497
+ primary: "oklch(0.929 0.013 255.508)",
25498
+ primaryForeground: "oklch(0.208 0.042 265.755)",
25499
+ secondary: "oklch(0.279 0.041 260.031)",
25500
+ secondaryForeground: "oklch(0.984 0.003 247.858)",
25501
+ muted: "oklch(0.279 0.041 260.031)",
25502
+ mutedForeground: "oklch(0.704 0.04 256.788)",
25503
+ accent: "oklch(0.279 0.041 260.031)",
25504
+ accentForeground: "oklch(0.984 0.003 247.858)",
25505
+ destructive: "oklch(0.704 0.191 22.216)",
25506
+ destructiveForeground: "oklch(0.704 0.191 22.216)",
25507
+ border: "oklch(1 0 0 / 10%)",
25508
+ input: "oklch(1 0 0 / 15%)",
25509
+ ring: "oklch(0.551 0.027 264.364)",
25510
+ chart1: "oklch(0.488 0.243 264.376)",
25511
+ chart2: "oklch(0.696 0.17 162.48)",
25512
+ chart3: "oklch(0.769 0.188 70.08)",
25513
+ chart4: "oklch(0.627 0.265 303.9)",
25514
+ chart5: "oklch(0.645 0.246 16.439)",
25515
+ sidebar: "oklch(0.208 0.042 265.755)",
25516
+ sidebarForeground: "oklch(0.984 0.003 247.858)",
25517
+ sidebarPrimary: "oklch(0.488 0.243 264.376)",
25518
+ sidebarPrimaryForeground: "oklch(0.984 0.003 247.858)",
25519
+ sidebarAccent: "oklch(0.279 0.041 260.031)",
25520
+ sidebarAccentForeground: "oklch(0.984 0.003 247.858)",
25521
+ sidebarBorder: "oklch(1 0 0 / 10%)",
25522
+ sidebarRing: "oklch(0.551 0.027 264.364)"
25523
+ }
25524
+ };
25525
+ var themes = {
25526
+ neutral: neutralTheme,
25527
+ gray: grayTheme,
25528
+ zinc: zincTheme,
25529
+ stone: stoneTheme,
25530
+ slate: slateTheme
25531
+ };
25532
+ function generateThemeCSS(theme, customRadius) {
25533
+ const radius = customRadius || theme.light.radius;
25534
+ return `@layer base {
25535
+ :root {
25536
+ --radius: ${radius};
25537
+ --background: ${theme.light.background};
25538
+ --foreground: ${theme.light.foreground};
25539
+ --card: ${theme.light.card};
25540
+ --card-foreground: ${theme.light.cardForeground};
25541
+ --popover: ${theme.light.popover};
25542
+ --popover-foreground: ${theme.light.popoverForeground};
25543
+ --primary: ${theme.light.primary};
25544
+ --primary-foreground: ${theme.light.primaryForeground};
25545
+ --secondary: ${theme.light.secondary};
25546
+ --secondary-foreground: ${theme.light.secondaryForeground};
25547
+ --muted: ${theme.light.muted};
25548
+ --muted-foreground: ${theme.light.mutedForeground};
25549
+ --accent: ${theme.light.accent};
25550
+ --accent-foreground: ${theme.light.accentForeground};
25551
+ --destructive: ${theme.light.destructive};
25552
+ --destructive-foreground: ${theme.light.destructiveForeground};
25553
+ --border: ${theme.light.border};
25554
+ --input: ${theme.light.input};
25555
+ --ring: ${theme.light.ring};
25556
+ --chart-1: ${theme.light.chart1};
25557
+ --chart-2: ${theme.light.chart2};
25558
+ --chart-3: ${theme.light.chart3};
25559
+ --chart-4: ${theme.light.chart4};
25560
+ --chart-5: ${theme.light.chart5};
25561
+ --sidebar: ${theme.light.sidebar};
25562
+ --sidebar-foreground: ${theme.light.sidebarForeground};
25563
+ --sidebar-primary: ${theme.light.sidebarPrimary};
25564
+ --sidebar-primary-foreground: ${theme.light.sidebarPrimaryForeground};
25565
+ --sidebar-accent: ${theme.light.sidebarAccent};
25566
+ --sidebar-accent-foreground: ${theme.light.sidebarAccentForeground};
25567
+ --sidebar-border: ${theme.light.sidebarBorder};
25568
+ --sidebar-ring: ${theme.light.sidebarRing};
25569
+ }
25570
+
25571
+ .dark {
25572
+ --background: ${theme.dark.background};
25573
+ --foreground: ${theme.dark.foreground};
25574
+ --card: ${theme.dark.card};
25575
+ --card-foreground: ${theme.dark.cardForeground};
25576
+ --popover: ${theme.dark.popover};
25577
+ --popover-foreground: ${theme.dark.popoverForeground};
25578
+ --primary: ${theme.dark.primary};
25579
+ --primary-foreground: ${theme.dark.primaryForeground};
25580
+ --secondary: ${theme.dark.secondary};
25581
+ --secondary-foreground: ${theme.dark.secondaryForeground};
25582
+ --muted: ${theme.dark.muted};
25583
+ --muted-foreground: ${theme.dark.mutedForeground};
25584
+ --accent: ${theme.dark.accent};
25585
+ --accent-foreground: ${theme.dark.accentForeground};
25586
+ --destructive: ${theme.dark.destructive};
25587
+ --destructive-foreground: ${theme.dark.destructiveForeground};
25588
+ --border: ${theme.dark.border};
25589
+ --input: ${theme.dark.input};
25590
+ --ring: ${theme.dark.ring};
25591
+ --chart-1: ${theme.dark.chart1};
25592
+ --chart-2: ${theme.dark.chart2};
25593
+ --chart-3: ${theme.dark.chart3};
25594
+ --chart-4: ${theme.dark.chart4};
25595
+ --chart-5: ${theme.dark.chart5};
25596
+ --sidebar: ${theme.dark.sidebar};
25597
+ --sidebar-foreground: ${theme.dark.sidebarForeground};
25598
+ --sidebar-primary: ${theme.dark.sidebarPrimary};
25599
+ --sidebar-primary-foreground: ${theme.dark.sidebarPrimaryForeground};
25600
+ --sidebar-accent: ${theme.dark.sidebarAccent};
25601
+ --sidebar-accent-foreground: ${theme.dark.sidebarAccentForeground};
25602
+ --sidebar-border: ${theme.dark.sidebarBorder};
25603
+ --sidebar-ring: ${theme.dark.sidebarRing};
25604
+ }
25605
+ }
25606
+
25607
+ @layer base {
25608
+ * {
25609
+ @apply border-border outline-ring/50;
25610
+ }
25611
+ body {
25612
+ @apply bg-background text-foreground;
25613
+ }
25614
+ }
25615
+ `;
25616
+ }
25617
+
25618
+ // ../templates/src/generators/shadcn-components.ts
25619
+ init_execa();
25620
+ init_dist();
25621
+ init_src();
25622
+ init_src();
25623
+ var DEFAULT_SHADCN_COMPONENTS = [
25624
+ "button",
25625
+ "card"
25626
+ ];
25627
+ async function installShadcnComponents(projectPath, components, options = {}) {
25628
+ const cwd2 = options.cwd || projectPath;
25629
+ const stdio = options.silent ? "pipe" : "inherit";
25630
+ try {
25631
+ await execa("bunx", ["shadcn@latest", "add", ...components], {
25632
+ cwd: cwd2,
25633
+ stdio
25634
+ });
25635
+ } catch (error) {
25636
+ try {
25637
+ await execa("npx", ["shadcn@latest", "add", ...components], {
25638
+ cwd: cwd2,
25639
+ stdio
25640
+ });
25641
+ } catch (fallbackError) {
25642
+ logger.warn(`Could not install shadcn components automatically. You can install them manually with: bunx shadcn@latest add ${components.join(" ")}`);
25643
+ }
25644
+ }
25645
+ }
25646
+ async function installDefaultShadcnComponents(projectPath, options = {}) {
25647
+ if (options.skipDefaults) {
25648
+ return;
25649
+ }
25650
+ logger.step("Installing default shadcn/ui components...");
25651
+ try {
25652
+ await installShadcnComponents(projectPath, [...DEFAULT_SHADCN_COMPONENTS], {
25653
+ silent: options.silent,
25654
+ cwd: projectPath
25655
+ });
25656
+ logger.success("Default components installed");
25657
+ } catch (error) {
25658
+ logger.warn("Could not install default components automatically. Install them manually with: bunx shadcn@latest add button card");
25659
+ }
25660
+ }
25661
+ async function createShadcnExample(projectPath, isMonorepo = false) {
25662
+ const examplePath = isMonorepo ? join(projectPath, "apps/web/src/components/example.tsx") : join(projectPath, "src/components/example.tsx");
25663
+ const exampleContent = `"use client"
25664
+
25665
+ import { Button } from "@/components/ui/button"
25666
+ import {
25667
+ Card,
25668
+ CardContent,
25669
+ CardDescription,
25670
+ CardFooter,
25671
+ CardHeader,
25672
+ CardTitle,
25673
+ } from "@/components/ui/card"
25674
+
25675
+ /**
25676
+ * Example component showcasing shadcn/ui components
25677
+ * This file demonstrates how to use Button and Card components
25678
+ *
25679
+ * You can delete this file once you're familiar with the patterns.
25680
+ */
25681
+ export function ExampleComponent() {
25682
+ return (
25683
+ <div className="container mx-auto p-8 space-y-6">
25684
+ <Card>
25685
+ <CardHeader>
25686
+ <CardTitle>Welcome to shadcn/ui</CardTitle>
25687
+ <CardDescription>
25688
+ This is an example component showing how to use shadcn/ui components.
25689
+ </CardDescription>
25690
+ </CardHeader>
25691
+ <CardContent>
25692
+ <p className="text-sm text-muted-foreground">
25693
+ You can start building your UI by importing components from @/components/ui
25694
+ </p>
25695
+ </CardContent>
25696
+ <CardFooter className="flex gap-2">
25697
+ <Button>Get Started</Button>
25698
+ <Button variant="outline">Learn More</Button>
25699
+ </CardFooter>
25700
+ </Card>
25701
+ </div>
25702
+ )
25703
+ }
25704
+ `;
25705
+ try {
25706
+ await ensureDirectory(join(examplePath, ".."));
25707
+ await writeFile(examplePath, exampleContent);
25708
+ } catch (error) {}
25709
+ }
25710
+
25711
+ // ../templates/src/generators/shadcn-docs.ts
25712
+ init_dist();
25713
+ init_src();
25714
+ async function createShadcnDocs(projectPath, isMonorepo = false, context) {
25715
+ const docsPath = isMonorepo ? join(projectPath, "packages/ui/SHADCN.md") : join(projectPath, "SHADCN.md");
25716
+ const docsContent = `# shadcn/ui Guide
25717
+
25718
+ This project uses [shadcn/ui](https://ui.shadcn.com) - a collection of re-usable components built with Radix UI and Tailwind CSS.
25719
+
25720
+ ## \uD83D\uDE80 Quick Start
25721
+
25722
+ ### Adding Components
25723
+
25724
+ Use the bunkit CLI to add components:
25725
+
25726
+ \`\`\`bash
25727
+ # Add a single component
25728
+ bunkit add component --components button
25729
+
25730
+ # Add multiple components
25731
+ bunkit add component --components button,card,input
25732
+
25733
+ # Browse all available components
25734
+ bunkit add component --all
25735
+ \`\`\`
25736
+
25737
+ Or use the official shadcn CLI directly:
25738
+
25739
+ \`\`\`bash
25740
+ bunx shadcn@latest add button
25741
+ bunx shadcn@latest add card
25742
+ bunx shadcn@latest add input
25743
+ \`\`\`
25744
+
25745
+ ### Using Components
25746
+
25747
+ Import components from the \`@/components/ui\` path:
25748
+
25749
+ \`\`\`tsx
25750
+ import { Button } from "@/components/ui/button"
25751
+ import {
25752
+ Card,
25753
+ CardContent,
25754
+ CardDescription,
25755
+ CardFooter,
25756
+ CardHeader,
25757
+ CardTitle,
25758
+ } from "@/components/ui/card"
25759
+
25760
+ export function MyComponent() {
25761
+ return (
25762
+ <Card>
25763
+ <CardHeader>
25764
+ <CardTitle>Hello</CardTitle>
25765
+ <CardDescription>World</CardDescription>
25766
+ </CardHeader>
25767
+ <CardContent>
25768
+ <Button>Click me</Button>
25769
+ </CardContent>
25770
+ </Card>
25771
+ )
25772
+ }
25773
+ \`\`\`
25774
+
25775
+ ## \uD83D\uDCDA Available Components
25776
+
25777
+ shadcn/ui provides 60+ components. Browse them all at [ui.shadcn.com](https://ui.shadcn.com/components).
25778
+
25779
+ ### Most Popular Components
25780
+
25781
+ - **Button** - \`bunkit add component --components button\`
25782
+ - **Card** - \`bunkit add component --components card\`
25783
+ - **Input** - \`bunkit add component --components input\`
25784
+ - **Dialog** - \`bunkit add component --components dialog\`
25785
+ - **Dropdown Menu** - \`bunkit add component --components dropdown-menu\`
25786
+ - **Form** - \`bunkit add component --components form\`
25787
+ - **Table** - \`bunkit add component --components table\`
25788
+ - **Toast** - \`bunkit add component --components toast\`
25789
+
25790
+ ## \uD83C\uDFA8 Customization
25791
+
25792
+ ### Themes
25793
+
25794
+ Your project is configured with:
25795
+ - **Style**: ${context?.shadcnStyle || "new-york"}
25796
+ - **Base Color**: ${context?.shadcnBaseColor || "zinc"}
25797
+ - **Border Radius**: ${context?.shadcnRadius || "0.625rem"}
25798
+
25799
+ ### Modifying Themes
25800
+
25801
+ Edit the CSS variables in \`${isMonorepo ? "packages/ui/src/styles/globals.css" : "src/app/globals.css"}\`:
25802
+
25803
+ \`\`\`css
25804
+ @layer base {
25805
+ :root {
25806
+ --radius: 0.625rem;
25807
+ --background: oklch(...);
25808
+ --foreground: oklch(...);
25809
+ /* ... */
25810
+ }
25811
+ }
25812
+ \`\`\`
25813
+
25814
+ ### Component Customization
25815
+
25816
+ Components are copied directly into your project at \`${isMonorepo ? "packages/ui/src/components/ui" : "src/components/ui"}\`. You can modify them directly - they're YOUR code!
25817
+
25818
+ ## \uD83D\uDCD6 Documentation
25819
+
25820
+ - [Official shadcn/ui Docs](https://ui.shadcn.com)
25821
+ - [Component Examples](https://ui.shadcn.com/components)
25822
+ - [Theming Guide](https://ui.shadcn.com/theming)
25823
+
25824
+ ## \uD83D\uDCA1 Tips
25825
+
25826
+ 1. **Components are yours** - They're copied into your project, so feel free to modify them
25827
+ 2. **Type-safe** - All components are fully typed with TypeScript
25828
+ 3. **Accessible** - Built on Radix UI primitives for accessibility
25829
+ 4. **Customizable** - Use Tailwind classes to style components however you want
25830
+
25831
+ ## \uD83D\uDD27 Configuration
25832
+
25833
+ Your \`components.json\` file (located at \`${isMonorepo ? "packages/ui/components.json" : "components.json"}\`) contains all shadcn/ui configuration.
25834
+
25835
+ To change settings, edit this file or run:
25836
+
25837
+ \`\`\`bash
25838
+ bunx shadcn@latest init
25839
+ \`\`\`
25840
+
25841
+ ---
25842
+
25843
+ **Happy building! \uD83D\uDE80**
25844
+ `;
25845
+ try {
25846
+ await ensureDirectory(join(docsPath, ".."));
25847
+ await writeFile(docsPath, docsContent);
25848
+ } catch (error) {}
25849
+ }
25850
+
25851
+ // ../templates/src/generators/shadcn.ts
25852
+ async function setupShadcnWeb(projectPath, context) {
25853
+ await ensureDirectory(join(projectPath, "src/components/ui"));
25854
+ await ensureDirectory(join(projectPath, "src/lib"));
25855
+ const style = context.shadcnStyle || "new-york";
25856
+ const baseColor = context.shadcnBaseColor || "zinc";
25857
+ const radius = context.shadcnRadius || "0.625rem";
25858
+ const componentsJson = {
25859
+ $schema: "https://ui.shadcn.com/schema.json",
25860
+ style,
25861
+ rsc: true,
25862
+ tsx: true,
25863
+ tailwind: {
25864
+ config: "",
25865
+ css: "src/app/globals.css",
25866
+ baseColor,
25867
+ cssVariables: true
25868
+ },
25869
+ iconLibrary: "lucide",
25870
+ aliases: {
25871
+ components: "@/components",
25872
+ utils: "@/lib/utils",
25873
+ ui: "@/components/ui",
25874
+ lib: "@/lib",
25875
+ hooks: "@/hooks"
25876
+ }
25877
+ };
25878
+ await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
25879
+ const utilsContent = `import { clsx, type ClassValue } from 'clsx';
25880
+ import { twMerge } from 'tailwind-merge';
25881
+
25882
+ export function cn(...inputs: ClassValue[]) {
25883
+ return twMerge(clsx(inputs));
25884
+ }
25885
+ `;
25886
+ await writeFile(join(projectPath, "src/lib/utils.ts"), utilsContent);
25887
+ const packageJsonPath = join(projectPath, "package.json");
25888
+ let packageJson = {};
25889
+ try {
25890
+ packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
25891
+ } catch {}
25892
+ if (!packageJson.dependencies) {
25893
+ packageJson.dependencies = {};
25894
+ }
25895
+ packageJson.dependencies["@radix-ui/react-slot"] = "catalog:";
25896
+ packageJson.dependencies["class-variance-authority"] = "catalog:";
25897
+ packageJson.dependencies["clsx"] = "catalog:";
25898
+ packageJson.dependencies["tailwind-merge"] = "catalog:";
25899
+ packageJson.dependencies["lucide-react"] = "catalog:";
25900
+ if (!packageJson.catalog) {
25901
+ packageJson.catalog = {};
25902
+ }
25903
+ packageJson.catalog["@radix-ui/react-slot"] = "^1.2.3";
25904
+ packageJson.catalog["class-variance-authority"] = "^0.7.1";
25905
+ packageJson.catalog["clsx"] = "^2.1.1";
25906
+ packageJson.catalog["tailwind-merge"] = "^3.3.1";
25907
+ packageJson.catalog["lucide-react"] = "^0.468.0";
25908
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
25909
+ const globalsCssPath = join(projectPath, "src/app/globals.css");
25910
+ let globalsCss = "";
25911
+ try {
25912
+ globalsCss = await Bun.file(globalsCssPath).text();
25913
+ } catch {}
25914
+ if (!globalsCss.includes("--background")) {
25915
+ const theme = themes[baseColor] || themes.zinc;
25916
+ const shadcnCss = generateThemeCSS(theme, radius);
25917
+ if (globalsCss) {
25918
+ globalsCss = globalsCss + `
25919
+ ` + shadcnCss;
25920
+ } else {
25921
+ globalsCss = `@import "tailwindcss";
25922
+
25923
+ ${shadcnCss}`;
25924
+ }
25925
+ await writeFile(globalsCssPath, globalsCss);
25926
+ }
25927
+ const tailwindConfigPath = join(projectPath, "tailwind.config.ts");
25928
+ let tailwindConfig = "";
25929
+ try {
25930
+ tailwindConfig = await Bun.file(tailwindConfigPath).text();
25931
+ } catch {}
25932
+ if (tailwindConfig && !tailwindConfig.includes("hsl(var(--background))")) {
25933
+ const shadcnTheme = ` theme: {
25934
+ extend: {
25935
+ colors: {
25936
+ border: "hsl(var(--border))",
25937
+ input: "hsl(var(--input))",
25938
+ ring: "hsl(var(--ring))",
25939
+ background: "hsl(var(--background))",
25940
+ foreground: "hsl(var(--foreground))",
25941
+ primary: {
25942
+ DEFAULT: "hsl(var(--primary))",
25943
+ foreground: "hsl(var(--primary-foreground))",
25944
+ },
25945
+ secondary: {
25946
+ DEFAULT: "hsl(var(--secondary))",
25947
+ foreground: "hsl(var(--secondary-foreground))",
25948
+ },
25949
+ destructive: {
25950
+ DEFAULT: "hsl(var(--destructive))",
25951
+ foreground: "hsl(var(--destructive-foreground))",
25952
+ },
25953
+ muted: {
25954
+ DEFAULT: "hsl(var(--muted))",
25955
+ foreground: "hsl(var(--muted-foreground))",
25956
+ },
25957
+ accent: {
25958
+ DEFAULT: "hsl(var(--accent))",
25959
+ foreground: "hsl(var(--accent-foreground))",
25960
+ },
25961
+ popover: {
25962
+ DEFAULT: "hsl(var(--popover))",
25963
+ foreground: "hsl(var(--popover-foreground))",
25964
+ },
25965
+ card: {
25966
+ DEFAULT: "hsl(var(--card))",
25967
+ foreground: "hsl(var(--card-foreground))",
25968
+ },
25969
+ },
25970
+ borderRadius: {
25971
+ lg: "var(--radius)",
25972
+ md: "calc(var(--radius) - 2px)",
25973
+ sm: "calc(var(--radius) - 4px)",
25974
+ },
25975
+ },
25976
+ },`;
25977
+ if (tailwindConfig.includes("theme:")) {
25978
+ const updatedConfig = tailwindConfig.replace(/theme:\s*\{[^}]*\}/s, shadcnTheme.trim());
25979
+ await writeFile(tailwindConfigPath, updatedConfig);
25980
+ } else {
25981
+ const updatedConfig = tailwindConfig.replace(/(\s*)(plugins:.*?)(\n\s*\};)/s, `$1$2$1${shadcnTheme}$3`);
25982
+ await writeFile(tailwindConfigPath, updatedConfig);
25983
+ }
25984
+ } else if (!tailwindConfig) {
25985
+ const newTailwindConfig = `import type { Config } from 'tailwindcss';
25986
+
25987
+ const config: Config = {
25988
+ content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
25989
+ theme: {
25990
+ extend: {
25991
+ colors: {
25992
+ border: "hsl(var(--border))",
25993
+ input: "hsl(var(--input))",
25994
+ ring: "hsl(var(--ring))",
25995
+ background: "hsl(var(--background))",
25996
+ foreground: "hsl(var(--foreground))",
25997
+ primary: {
25998
+ DEFAULT: "hsl(var(--primary))",
25999
+ foreground: "hsl(var(--primary-foreground))",
26000
+ },
26001
+ secondary: {
26002
+ DEFAULT: "hsl(var(--secondary))",
26003
+ foreground: "hsl(var(--secondary-foreground))",
26004
+ },
26005
+ destructive: {
26006
+ DEFAULT: "hsl(var(--destructive))",
26007
+ foreground: "hsl(var(--destructive-foreground))",
26008
+ },
26009
+ muted: {
26010
+ DEFAULT: "hsl(var(--muted))",
26011
+ foreground: "hsl(var(--muted-foreground))",
26012
+ },
26013
+ accent: {
26014
+ DEFAULT: "hsl(var(--accent))",
26015
+ foreground: "hsl(var(--accent-foreground))",
26016
+ },
26017
+ popover: {
26018
+ DEFAULT: "hsl(var(--popover))",
26019
+ foreground: "hsl(var(--popover-foreground))",
26020
+ },
26021
+ card: {
26022
+ DEFAULT: "hsl(var(--card))",
26023
+ foreground: "hsl(var(--card-foreground))",
26024
+ },
26025
+ },
26026
+ borderRadius: {
26027
+ lg: "var(--radius)",
26028
+ md: "calc(var(--radius) - 2px)",
26029
+ sm: "calc(var(--radius) - 4px)",
26030
+ },
26031
+ },
26032
+ },
26033
+ plugins: [],
26034
+ };
26035
+
26036
+ export default config;
26037
+ `;
26038
+ await writeFile(tailwindConfigPath, newTailwindConfig);
26039
+ }
26040
+ if (context.install !== false) {}
26041
+ await createShadcnExample(projectPath, false);
26042
+ await createShadcnDocs(projectPath, false, context);
26043
+ }
26044
+ async function setupShadcnMonorepo(projectPath, context) {
26045
+ const packageName = context.packageName || context.projectName.toLowerCase().replace(/\s+/g, "-");
26046
+ const uiPackageName = `@${packageName}/ui`;
26047
+ const style = context.shadcnStyle || "new-york";
26048
+ const baseColor = context.shadcnBaseColor || "zinc";
26049
+ const radius = context.shadcnRadius || "0.625rem";
26050
+ await ensureDirectory(join(projectPath, "packages/ui/src/components"));
26051
+ await ensureDirectory(join(projectPath, "packages/ui/src/lib"));
26052
+ await ensureDirectory(join(projectPath, "packages/ui/src/hooks"));
26053
+ await ensureDirectory(join(projectPath, "packages/ui/src/styles"));
26054
+ const uiPackageJson = {
26055
+ name: uiPackageName,
26056
+ version: "0.0.0",
26057
+ private: true,
26058
+ main: "./src/index.ts",
26059
+ types: "./src/index.ts",
26060
+ exports: {
26061
+ "./components": "./src/components/index.ts",
26062
+ "./lib/utils": "./src/lib/utils.ts",
26063
+ "./hooks": "./src/hooks/index.ts",
26064
+ "./styles": "./src/styles/globals.css"
26065
+ },
26066
+ dependencies: {
26067
+ "@radix-ui/react-slot": "catalog:",
26068
+ "class-variance-authority": "catalog:",
26069
+ clsx: "catalog:",
26070
+ "tailwind-merge": "catalog:",
26071
+ "lucide-react": "catalog:"
26072
+ },
26073
+ devDependencies: {
26074
+ "@types/react": "catalog:",
26075
+ "@types/react-dom": "catalog:",
26076
+ typescript: "catalog:"
26077
+ }
26078
+ };
26079
+ await writeFile(join(projectPath, "packages/ui/package.json"), JSON.stringify(uiPackageJson, null, 2));
26080
+ const uiComponentsJson = {
26081
+ $schema: "https://ui.shadcn.com/schema.json",
26082
+ style,
26083
+ rsc: true,
26084
+ tsx: true,
26085
+ tailwind: {
26086
+ config: "",
26087
+ css: "src/styles/globals.css",
26088
+ baseColor,
26089
+ cssVariables: true
26090
+ },
26091
+ iconLibrary: "lucide",
26092
+ aliases: {
26093
+ components: "@workspace/ui/components",
26094
+ utils: "@workspace/ui/lib/utils",
26095
+ hooks: "@workspace/ui/hooks",
26096
+ lib: "@workspace/ui/lib",
26097
+ ui: "@workspace/ui/components"
26098
+ }
26099
+ };
26100
+ await writeFile(join(projectPath, "packages/ui/components.json"), JSON.stringify(uiComponentsJson, null, 2));
26101
+ const uiUtilsContent = `import { clsx, type ClassValue } from 'clsx';
26102
+ import { twMerge } from 'tailwind-merge';
26103
+
26104
+ export function cn(...inputs: ClassValue[]) {
26105
+ return twMerge(clsx(inputs));
26106
+ }
26107
+ `;
26108
+ await writeFile(join(projectPath, "packages/ui/src/lib/utils.ts"), uiUtilsContent);
26109
+ const uiComponentsIndex = `// Export shadcn/ui components here
26110
+ // Components will be added via: bunx shadcn@latest add [component]
26111
+ `;
26112
+ await writeFile(join(projectPath, "packages/ui/src/components/index.ts"), uiComponentsIndex);
26113
+ const uiHooksIndex = `// Export custom hooks here
26114
+ `;
26115
+ await writeFile(join(projectPath, "packages/ui/src/hooks/index.ts"), uiHooksIndex);
26116
+ const theme = themes[baseColor] || themes.zinc;
26117
+ const uiGlobalsCss = generateThemeCSS(theme, radius);
26118
+ await writeFile(join(projectPath, "packages/ui/src/styles/globals.css"), uiGlobalsCss);
26119
+ const uiTsconfig = {
26120
+ compilerOptions: {
26121
+ target: "ES2017",
26122
+ lib: ["dom", "dom.iterable", "esnext"],
26123
+ allowJs: true,
26124
+ skipLibCheck: true,
26125
+ strict: true,
26126
+ noEmit: true,
26127
+ esModuleInterop: true,
26128
+ module: "esnext",
26129
+ moduleResolution: "bundler",
26130
+ resolveJsonModule: true,
26131
+ isolatedModules: true,
26132
+ jsx: "react-jsx",
26133
+ types: ["react", "react-dom"]
26134
+ },
26135
+ include: ["src/**/*"],
26136
+ exclude: ["node_modules"]
26137
+ };
26138
+ await writeFile(join(projectPath, "packages/ui/tsconfig.json"), JSON.stringify(uiTsconfig, null, 2));
26139
+ await ensureDirectory(join(projectPath, "apps/web/src/components"));
26140
+ await ensureDirectory(join(projectPath, "apps/web/src/lib"));
26141
+ const webComponentsJson = {
26142
+ $schema: "https://ui.shadcn.com/schema.json",
26143
+ style,
26144
+ rsc: true,
26145
+ tsx: true,
26146
+ tailwind: {
26147
+ config: "",
26148
+ css: "../../packages/ui/src/styles/globals.css",
26149
+ baseColor,
26150
+ cssVariables: true
26151
+ },
26152
+ iconLibrary: "lucide",
26153
+ aliases: {
26154
+ components: "@/components",
26155
+ hooks: "@/hooks",
26156
+ lib: "@/lib",
26157
+ utils: "@workspace/ui/lib/utils",
26158
+ ui: "@workspace/ui/components"
26159
+ }
26160
+ };
26161
+ await writeFile(join(projectPath, "apps/web/components.json"), JSON.stringify(webComponentsJson, null, 2));
26162
+ const webGlobalsCssPath = join(projectPath, "apps/web/src/app/globals.css");
26163
+ const webGlobalsCss = `@import "../../../packages/ui/src/styles/globals.css";
26164
+ `;
26165
+ await writeFile(webGlobalsCssPath, webGlobalsCss);
26166
+ const webPackageJsonPath = join(projectPath, "apps/web/package.json");
26167
+ let webPackageJson = {};
26168
+ try {
26169
+ webPackageJson = JSON.parse(await Bun.file(webPackageJsonPath).text());
26170
+ } catch {}
26171
+ if (webPackageJson.dependencies) {
26172
+ webPackageJson.dependencies[uiPackageName] = "workspace:*";
26173
+ await writeFile(webPackageJsonPath, JSON.stringify(webPackageJson, null, 2));
26174
+ }
26175
+ await ensureDirectory(join(projectPath, "apps/platform/src/components"));
26176
+ await ensureDirectory(join(projectPath, "apps/platform/src/lib"));
26177
+ const platformComponentsJson = {
26178
+ $schema: "https://ui.shadcn.com/schema.json",
26179
+ style,
26180
+ rsc: true,
26181
+ tsx: true,
26182
+ tailwind: {
26183
+ config: "",
26184
+ css: "../../packages/ui/src/styles/globals.css",
26185
+ baseColor,
26186
+ cssVariables: true
26187
+ },
26188
+ iconLibrary: "lucide",
26189
+ aliases: {
26190
+ components: "@/components",
26191
+ hooks: "@/hooks",
26192
+ lib: "@/lib",
26193
+ utils: "@workspace/ui/lib/utils",
26194
+ ui: "@workspace/ui/components"
26195
+ }
26196
+ };
26197
+ await writeFile(join(projectPath, "apps/platform/components.json"), JSON.stringify(platformComponentsJson, null, 2));
26198
+ const platformGlobalsCssPath = join(projectPath, "apps/platform/src/app/globals.css");
26199
+ const platformGlobalsCss = `@import "../../../packages/ui/src/styles/globals.css";
26200
+ `;
26201
+ await writeFile(platformGlobalsCssPath, platformGlobalsCss);
26202
+ const platformPackageJsonPath = join(projectPath, "apps/platform/package.json");
26203
+ let platformPackageJson = {};
26204
+ try {
26205
+ platformPackageJson = JSON.parse(await Bun.file(platformPackageJsonPath).text());
26206
+ } catch {}
26207
+ if (platformPackageJson.dependencies) {
26208
+ platformPackageJson.dependencies[uiPackageName] = "workspace:*";
26209
+ await writeFile(platformPackageJsonPath, JSON.stringify(platformPackageJson, null, 2));
26210
+ }
26211
+ const updateAppTailwindConfig = async (appPath) => {
26212
+ const tailwindConfigPath = join(projectPath, appPath, "tailwind.config.ts");
26213
+ let tailwindConfig = "";
26214
+ try {
26215
+ tailwindConfig = await Bun.file(tailwindConfigPath).text();
26216
+ } catch {}
26217
+ const shadcnTheme = ` theme: {
26218
+ extend: {
26219
+ colors: {
26220
+ border: "hsl(var(--border))",
26221
+ input: "hsl(var(--input))",
26222
+ ring: "hsl(var(--ring))",
26223
+ background: "hsl(var(--background))",
26224
+ foreground: "hsl(var(--foreground))",
26225
+ primary: {
26226
+ DEFAULT: "hsl(var(--primary))",
26227
+ foreground: "hsl(var(--primary-foreground))",
26228
+ },
26229
+ secondary: {
26230
+ DEFAULT: "hsl(var(--secondary))",
26231
+ foreground: "hsl(var(--secondary-foreground))",
26232
+ },
26233
+ destructive: {
26234
+ DEFAULT: "hsl(var(--destructive))",
26235
+ foreground: "hsl(var(--destructive-foreground))",
26236
+ },
26237
+ muted: {
26238
+ DEFAULT: "hsl(var(--muted))",
26239
+ foreground: "hsl(var(--muted-foreground))",
26240
+ },
26241
+ accent: {
26242
+ DEFAULT: "hsl(var(--accent))",
26243
+ foreground: "hsl(var(--accent-foreground))",
26244
+ },
26245
+ popover: {
26246
+ DEFAULT: "hsl(var(--popover))",
26247
+ foreground: "hsl(var(--popover-foreground))",
26248
+ },
26249
+ card: {
26250
+ DEFAULT: "hsl(var(--card))",
26251
+ foreground: "hsl(var(--card-foreground))",
26252
+ },
26253
+ },
26254
+ borderRadius: {
26255
+ lg: "var(--radius)",
26256
+ md: "calc(var(--radius) - 2px)",
26257
+ sm: "calc(var(--radius) - 4px)",
26258
+ },
26259
+ },
26260
+ },`;
26261
+ if (tailwindConfig && !tailwindConfig.includes("hsl(var(--background))")) {
26262
+ if (tailwindConfig.includes("theme:")) {
26263
+ const updatedConfig = tailwindConfig.replace(/theme:\s*\{[^}]*\}/s, shadcnTheme.trim());
26264
+ await writeFile(tailwindConfigPath, updatedConfig);
26265
+ } else {
26266
+ const updatedConfig = tailwindConfig.replace(/(\s*)(plugins:.*?)(\n\s*\};)/s, `$1$2$1${shadcnTheme}$3`);
26267
+ await writeFile(tailwindConfigPath, updatedConfig);
26268
+ }
26269
+ } else if (!tailwindConfig) {
26270
+ const newTailwindConfig = `import type { Config } from 'tailwindcss';
26271
+
26272
+ const config: Config = {
26273
+ content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
26274
+ theme: {
26275
+ extend: {
26276
+ colors: {
26277
+ border: "hsl(var(--border))",
26278
+ input: "hsl(var(--input))",
26279
+ ring: "hsl(var(--ring))",
26280
+ background: "hsl(var(--background))",
26281
+ foreground: "hsl(var(--foreground))",
26282
+ primary: {
26283
+ DEFAULT: "hsl(var(--primary))",
26284
+ foreground: "hsl(var(--primary-foreground))",
26285
+ },
26286
+ secondary: {
26287
+ DEFAULT: "hsl(var(--secondary))",
26288
+ foreground: "hsl(var(--secondary-foreground))",
26289
+ },
26290
+ destructive: {
26291
+ DEFAULT: "hsl(var(--destructive))",
26292
+ foreground: "hsl(var(--destructive-foreground))",
26293
+ },
26294
+ muted: {
26295
+ DEFAULT: "hsl(var(--muted))",
26296
+ foreground: "hsl(var(--muted-foreground))",
26297
+ },
26298
+ accent: {
26299
+ DEFAULT: "hsl(var(--accent))",
26300
+ foreground: "hsl(var(--accent-foreground))",
26301
+ },
26302
+ popover: {
26303
+ DEFAULT: "hsl(var(--popover))",
26304
+ foreground: "hsl(var(--popover-foreground))",
26305
+ },
26306
+ card: {
26307
+ DEFAULT: "hsl(var(--card))",
26308
+ foreground: "hsl(var(--card-foreground))",
26309
+ },
26310
+ },
26311
+ borderRadius: {
26312
+ lg: "var(--radius)",
26313
+ md: "calc(var(--radius) - 2px)",
26314
+ sm: "calc(var(--radius) - 4px)",
26315
+ },
26316
+ },
26317
+ },
26318
+ plugins: [],
26319
+ };
26320
+
26321
+ export default config;
26322
+ `;
26323
+ await writeFile(tailwindConfigPath, newTailwindConfig);
26324
+ }
26325
+ };
26326
+ await updateAppTailwindConfig("apps/web");
26327
+ await updateAppTailwindConfig("apps/platform");
26328
+ const rootPackageJsonPath = join(projectPath, "package.json");
26329
+ let rootPackageJson = {};
26330
+ try {
26331
+ rootPackageJson = JSON.parse(await Bun.file(rootPackageJsonPath).text());
26332
+ } catch {}
26333
+ if (rootPackageJson.catalog) {
26334
+ rootPackageJson.catalog["lucide-react"] = "^0.468.0";
26335
+ await writeFile(rootPackageJsonPath, JSON.stringify(rootPackageJson, null, 2));
26336
+ }
26337
+ await createShadcnExample(join(projectPath, "apps/web"), true);
26338
+ await createShadcnExample(join(projectPath, "apps/platform"), true);
26339
+ await createShadcnDocs(join(projectPath, "packages/ui"), true, context);
26340
+ }
26341
+
25077
26342
  // ../templates/src/builders/web.ts
25078
26343
  async function buildWebPreset(projectPath, context) {
25079
26344
  await ensureDirectory(join(projectPath, "src/app"));
@@ -25205,6 +26470,9 @@ export default config;
25205
26470
  if (context.cicd) {
25206
26471
  await setupGitHubActions(projectPath, context);
25207
26472
  }
26473
+ if (context.uiLibrary === "shadcn" && context.cssFramework === "tailwind") {
26474
+ await setupShadcnWeb(projectPath, context);
26475
+ }
25208
26476
  }
25209
26477
  // ../templates/src/builders/api.ts
25210
26478
  init_dist();
@@ -25252,7 +26520,114 @@ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/${context.projectName
25252
26520
  `;
25253
26521
  await writeFile(join(projectPath, ".env.example"), envExample);
25254
26522
  }
25255
- async function setupSupabase(projectPath, context, isMonorepo = false) {
26523
+ async function setupSupabaseOnly(projectPath, context, isMonorepo = false) {
26524
+ const dbPath = isMonorepo ? join(projectPath, "packages/db") : join(projectPath, "src/db");
26525
+ await ensureDirectory(dbPath);
26526
+ const features = context.supabaseFeatures || ["auth", "storage", "realtime", "database"];
26527
+ const hasAuth = features.includes("auth");
26528
+ const hasStorage = features.includes("storage");
26529
+ const hasRealtime = features.includes("realtime");
26530
+ const hasEdgeFunctions = features.includes("edge-functions");
26531
+ const hasDatabase = features.includes("database");
26532
+ const clientContent = `import { createClient } from '@supabase/supabase-js';
26533
+
26534
+ // Supabase client
26535
+ export const supabase = createClient(
26536
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
26537
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
26538
+ {
26539
+ auth: {
26540
+ autoRefreshToken: true,
26541
+ persistSession: true,
26542
+ detectSessionInUrl: true,
26543
+ },
26544
+ }
26545
+ );
26546
+
26547
+ ${hasAuth ? `// Auth helpers
26548
+ export const auth = supabase.auth;` : ""}
26549
+
26550
+ ${hasStorage ? `// Storage helpers
26551
+ export const storage = supabase.storage;` : ""}
26552
+
26553
+ ${hasRealtime ? `// Realtime helpers
26554
+ export const realtime = supabase.realtime;` : ""}
26555
+
26556
+ ${hasEdgeFunctions ? `// Edge Functions helpers
26557
+ export const functions = supabase.functions;` : ""}
26558
+
26559
+ ${hasDatabase ? `// Database helpers (using Supabase client directly)
26560
+ export const db = supabase.from;` : ""}
26561
+ `;
26562
+ await writeFile(join(dbPath, "index.ts"), clientContent);
26563
+ const examplesContent = `// Supabase usage examples
26564
+ import { supabase${hasAuth ? ", auth" : ""}${hasStorage ? ", storage" : ""}${hasRealtime ? ", realtime" : ""}${hasEdgeFunctions ? ", functions" : ""}${hasDatabase ? ", db" : ""} } from './index';
26565
+
26566
+ ${hasAuth ? `// Auth example
26567
+ export async function signUp(email: string, password: string) {
26568
+ const { data, error } = await auth.signUp({
26569
+ email,
26570
+ password,
26571
+ });
26572
+ return { data, error };
26573
+ }
26574
+
26575
+ export async function signIn(email: string, password: string) {
26576
+ const { data, error } = await auth.signInWithPassword({
26577
+ email,
26578
+ password,
26579
+ });
26580
+ return { data, error };
26581
+ }
26582
+
26583
+ export async function signOut() {
26584
+ const { error } = await auth.signOut();
26585
+ return { error };
26586
+ }` : ""}
26587
+
26588
+ ${hasStorage ? `// Storage example
26589
+ export async function uploadFile(bucket: string, path: string, file: File) {
26590
+ const { data, error } = await storage.from(bucket).upload(path, file);
26591
+ return { data, error };
26592
+ }
26593
+
26594
+ export function getPublicUrl(bucket: string, path: string) {
26595
+ const { data } = storage.from(bucket).getPublicUrl(path);
26596
+ return data.publicUrl;
26597
+ }` : ""}
26598
+
26599
+ ${hasRealtime ? `// Realtime example
26600
+ export function subscribeToChannel(channel: string, callback: (payload: any) => void) {
26601
+ const channelInstance = realtime.channel(channel);
26602
+ channelInstance.on('postgres_changes', { event: '*', schema: 'public', table: '*' }, callback);
26603
+ channelInstance.subscribe();
26604
+ return channelInstance;
26605
+ }` : ""}
26606
+
26607
+ ${hasEdgeFunctions ? `// Edge Functions example
26608
+ export async function invokeFunction(functionName: string, body?: any) {
26609
+ const { data, error } = await functions.invoke(functionName, { body });
26610
+ return { data, error };
26611
+ }` : ""}
26612
+
26613
+ ${hasDatabase ? `// Database example (using Supabase client directly)
26614
+ export async function getUsers() {
26615
+ const { data, error } = await supabase.from('users').select('*');
26616
+ return { data, error };
26617
+ }` : ""}
26618
+ `;
26619
+ await writeFile(join(dbPath, "examples.ts"), examplesContent);
26620
+ if (hasEdgeFunctions) {
26621
+ await ensureDirectory(join(projectPath, "supabase/functions"));
26622
+ }
26623
+ const envExample = `# Supabase
26624
+ NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
26625
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
26626
+ ${hasDatabase ? "DATABASE_URL=postgresql://postgres:[password]@db.your-project.supabase.co:5432/postgres" : ""}
26627
+ `;
26628
+ await writeFile(join(projectPath, ".env.example"), envExample);
26629
+ }
26630
+ async function setupSupabaseDrizzle(projectPath, context, isMonorepo = false) {
25256
26631
  const dbPath = isMonorepo ? join(projectPath, "packages/db") : join(projectPath, "src/db");
25257
26632
  await ensureDirectory(join(dbPath, "schema"));
25258
26633
  const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
@@ -25267,6 +26642,12 @@ export default defineConfig({
25267
26642
  });
25268
26643
  `;
25269
26644
  await writeFile(join(isMonorepo ? join(projectPath, "packages/db") : projectPath, "drizzle.config.ts"), drizzleConfig);
26645
+ const features = context.supabaseFeatures || ["auth", "storage", "realtime", "database"];
26646
+ const hasAuth = features.includes("auth");
26647
+ const hasStorage = features.includes("storage");
26648
+ const hasRealtime = features.includes("realtime");
26649
+ const hasEdgeFunctions = features.includes("edge-functions");
26650
+ const hasDatabase = features.includes("database");
25270
26651
  const clientContent = `import { createClient } from '@supabase/supabase-js';
25271
26652
  import { drizzle } from 'drizzle-orm/postgres-js';
25272
26653
  import postgres from 'postgres';
@@ -25275,14 +26656,95 @@ import * as schema from './schema';
25275
26656
  // Supabase client for auth, storage, realtime
25276
26657
  export const supabase = createClient(
25277
26658
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
25278
- process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
26659
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
26660
+ {
26661
+ auth: {
26662
+ autoRefreshToken: true,
26663
+ persistSession: true,
26664
+ detectSessionInUrl: true,
26665
+ },
26666
+ }
25279
26667
  );
25280
26668
 
26669
+ ${hasAuth ? `// Auth helpers
26670
+ export const auth = supabase.auth;` : ""}
26671
+
26672
+ ${hasStorage ? `// Storage helpers
26673
+ export const storage = supabase.storage;` : ""}
26674
+
26675
+ ${hasRealtime ? `// Realtime helpers
26676
+ export const realtime = supabase.realtime;` : ""}
26677
+
26678
+ ${hasEdgeFunctions ? `// Edge Functions helpers
26679
+ export const functions = supabase.functions;` : ""}
26680
+
25281
26681
  // Drizzle client for type-safe database queries
25282
- const queryClient = postgres(process.env.DATABASE_URL!);
25283
- export const db = drizzle(queryClient, { schema });
26682
+ ${hasDatabase ? `const queryClient = postgres(process.env.DATABASE_URL!);
26683
+ export const db = drizzle(queryClient, { schema });` : "// Database queries via Drizzle ORM"}
25284
26684
  `;
25285
26685
  await writeFile(join(dbPath, "index.ts"), clientContent);
26686
+ const examplesContent = `// Supabase + Drizzle usage examples
26687
+ import { supabase${hasAuth ? ", auth" : ""}${hasStorage ? ", storage" : ""}${hasRealtime ? ", realtime" : ""}${hasEdgeFunctions ? ", functions" : ""}, db } from './index';
26688
+ import { users } from './schema';
26689
+ import { eq } from 'drizzle-orm';
26690
+
26691
+ ${hasAuth ? `// Auth example
26692
+ export async function signUp(email: string, password: string) {
26693
+ const { data, error } = await auth.signUp({
26694
+ email,
26695
+ password,
26696
+ });
26697
+ return { data, error };
26698
+ }
26699
+
26700
+ export async function signIn(email: string, password: string) {
26701
+ const { data, error } = await auth.signInWithPassword({
26702
+ email,
26703
+ password,
26704
+ });
26705
+ return { data, error };
26706
+ }
26707
+
26708
+ export async function signOut() {
26709
+ const { error } = await auth.signOut();
26710
+ return { error };
26711
+ }` : ""}
26712
+
26713
+ ${hasStorage ? `// Storage example
26714
+ export async function uploadFile(bucket: string, path: string, file: File) {
26715
+ const { data, error } = await storage.from(bucket).upload(path, file);
26716
+ return { data, error };
26717
+ }
26718
+
26719
+ export function getPublicUrl(bucket: string, path: string) {
26720
+ const { data } = storage.from(bucket).getPublicUrl(path);
26721
+ return data.publicUrl;
26722
+ }` : ""}
26723
+
26724
+ ${hasRealtime ? `// Realtime example
26725
+ export function subscribeToChannel(channel: string, callback: (payload: any) => void) {
26726
+ const channelInstance = realtime.channel(channel);
26727
+ channelInstance.on('postgres_changes', { event: '*', schema: 'public', table: '*' }, callback);
26728
+ channelInstance.subscribe();
26729
+ return channelInstance;
26730
+ }` : ""}
26731
+
26732
+ ${hasEdgeFunctions ? `// Edge Functions example
26733
+ export async function invokeFunction(functionName: string, body?: any) {
26734
+ const { data, error } = await functions.invoke(functionName, { body });
26735
+ return { data, error };
26736
+ }` : ""}
26737
+
26738
+ ${hasDatabase ? `// Database example (using Drizzle ORM)
26739
+ export async function getUsers() {
26740
+ return await db.select().from(users);
26741
+ }
26742
+
26743
+ export async function getUserById(id: string) {
26744
+ return await db.select().from(users).where(eq(users.id, id));
26745
+ }` : ""}
26746
+ `;
26747
+ await writeFile(join(dbPath, "examples.ts"), examplesContent);
25286
26748
  const schemaContent = `import { pgTable, text, timestamp, uuid, boolean } from 'drizzle-orm/pg-core';
25287
26749
 
25288
26750
  export const users = pgTable('users', {
@@ -25306,10 +26768,13 @@ export const profiles = pgTable('profiles', {
25306
26768
  `;
25307
26769
  await writeFile(join(dbPath, "schema/index.ts"), schemaContent);
25308
26770
  await ensureDirectory(join(projectPath, "supabase/migrations"));
26771
+ if (hasEdgeFunctions) {
26772
+ await ensureDirectory(join(projectPath, "supabase/functions"));
26773
+ }
25309
26774
  const envExample = `# Supabase
25310
26775
  NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
25311
26776
  NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
25312
- DATABASE_URL=postgresql://postgres:[password]@db.your-project.supabase.co:5432/postgres
26777
+ ${hasDatabase ? "DATABASE_URL=postgresql://postgres:[password]@db.your-project.supabase.co:5432/postgres" : ""}
25313
26778
  `;
25314
26779
  await writeFile(join(projectPath, ".env.example"), envExample);
25315
26780
  }
@@ -25369,6 +26834,10 @@ function getDatabaseDependencies(databaseType) {
25369
26834
  postgres: "^3.4.5"
25370
26835
  };
25371
26836
  case "supabase":
26837
+ return {
26838
+ "@supabase/supabase-js": "^2.48.1"
26839
+ };
26840
+ case "supabase-drizzle":
25372
26841
  return {
25373
26842
  "@supabase/supabase-js": "^2.48.1",
25374
26843
  "drizzle-orm": "^0.38.0",
@@ -25555,7 +27024,9 @@ coverage = true
25555
27024
  if (context.database === "postgres-drizzle") {
25556
27025
  await setupPostgresDrizzle(projectPath, context, false);
25557
27026
  } else if (context.database === "supabase") {
25558
- await setupSupabase(projectPath, context, false);
27027
+ await setupSupabaseOnly(projectPath, context, false);
27028
+ } else if (context.database === "supabase-drizzle") {
27029
+ await setupSupabaseDrizzle(projectPath, context, false);
25559
27030
  } else if (context.database === "sqlite-drizzle") {
25560
27031
  await setupSQLiteDrizzle(projectPath, context, false);
25561
27032
  }
@@ -25619,6 +27090,7 @@ async function buildFullPreset(projectPath, context) {
25619
27090
  clsx: "^2.1.1",
25620
27091
  "tailwind-merge": "^3.3.1",
25621
27092
  "iconoir-react": "^7.11.0",
27093
+ "lucide-react": "^0.468.0",
25622
27094
  "@biomejs/biome": "^2.3.0",
25623
27095
  ultracite: "^6.0.1",
25624
27096
  vitest: "^2.0.0",
@@ -26138,14 +27610,21 @@ Built with \u2764\uFE0F using Bun monorepo features
26138
27610
  main: "./src/index.ts",
26139
27611
  types: "./src/index.ts",
26140
27612
  dependencies: context.database === "supabase" ? {
27613
+ "@supabase/supabase-js": "catalog:"
27614
+ } : context.database === "supabase-drizzle" ? {
26141
27615
  "@supabase/supabase-js": "catalog:",
26142
27616
  "drizzle-orm": "catalog:",
26143
27617
  postgres: "catalog:"
26144
- } : {
27618
+ } : context.database === "postgres-drizzle" ? {
27619
+ "drizzle-orm": "catalog:",
27620
+ postgres: "catalog:"
27621
+ } : context.database === "sqlite-drizzle" ? {
26145
27622
  "drizzle-orm": "catalog:"
26146
- },
27623
+ } : {},
26147
27624
  devDependencies: {
26148
- "drizzle-kit": "catalog:",
27625
+ ...context.database === "postgres-drizzle" || context.database === "supabase-drizzle" || context.database === "sqlite-drizzle" ? {
27626
+ "drizzle-kit": "catalog:"
27627
+ } : {},
26149
27628
  "@types/bun": "latest",
26150
27629
  typescript: "catalog:"
26151
27630
  }
@@ -26154,7 +27633,9 @@ Built with \u2764\uFE0F using Bun monorepo features
26154
27633
  if (context.database === "postgres-drizzle") {
26155
27634
  await setupPostgresDrizzle(dbPackagePath, context, true);
26156
27635
  } else if (context.database === "supabase") {
26157
- await setupSupabase(dbPackagePath, context, true);
27636
+ await setupSupabaseOnly(dbPackagePath, context, true);
27637
+ } else if (context.database === "supabase-drizzle") {
27638
+ await setupSupabaseDrizzle(dbPackagePath, context, true);
26158
27639
  } else if (context.database === "sqlite-drizzle") {
26159
27640
  await setupSQLiteDrizzle(dbPackagePath, context, true);
26160
27641
  }
@@ -26180,7 +27661,7 @@ services:
26180
27661
  - "3000:3000"
26181
27662
  environment:
26182
27663
  - NODE_ENV=production
26183
- ${context.database === "supabase" ? "- NEXT_PUBLIC_SUPABASE_URL=${SUPABASE_URL}\n - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}" : ""}
27664
+ ${context.database === "supabase" || context.database === "supabase-drizzle" ? "- NEXT_PUBLIC_SUPABASE_URL=${SUPABASE_URL}\n - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}" : ""}
26184
27665
  restart: unless-stopped
26185
27666
 
26186
27667
  platform:
@@ -26191,7 +27672,7 @@ services:
26191
27672
  - "3001:3000"
26192
27673
  environment:
26193
27674
  - NODE_ENV=production
26194
- ${context.database === "supabase" ? "- NEXT_PUBLIC_SUPABASE_URL=${SUPABASE_URL}\n - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}" : ""}
27675
+ ${context.database === "supabase" || context.database === "supabase-drizzle" ? "- NEXT_PUBLIC_SUPABASE_URL=${SUPABASE_URL}\n - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}" : ""}
26195
27676
  restart: unless-stopped
26196
27677
 
26197
27678
  api:
@@ -26228,6 +27709,9 @@ ${context.database && context.database !== "none" && context.database !== "supab
26228
27709
  if (context.cicd) {
26229
27710
  await setupGitHubActions(projectPath, context);
26230
27711
  }
27712
+ if (context.uiLibrary === "shadcn" && context.cssFramework === "tailwind") {
27713
+ await setupShadcnMonorepo(projectPath, context);
27714
+ }
26231
27715
  }
26232
27716
  // ../templates/src/builders/workspace.ts
26233
27717
  init_dist();
@@ -26508,7 +27992,7 @@ async function enhancedInitCommand(options = {}) {
26508
27992
  throw new Error("Project name is required in non-interactive mode. " + "Provide it via BUNKIT_PROJECT_NAME env var or --name flag.");
26509
27993
  }
26510
27994
  projectName = await he({
26511
- message: "\uD83D\uDCE6 What is your project named?",
27995
+ message: "\uD83D\uDCE6 Project name",
26512
27996
  placeholder: "my-awesome-project",
26513
27997
  validate: (value) => {
26514
27998
  const result = validateProjectName(value);
@@ -26532,27 +28016,27 @@ async function enhancedInitCommand(options = {}) {
26532
28016
  throw new Error("Preset is required in non-interactive mode. " + "Provide it via BUNKIT_PRESET env var or --preset flag.");
26533
28017
  }
26534
28018
  preset = await ve({
26535
- message: "\uD83C\uDFA8 Which preset would you like?",
28019
+ message: "\uD83C\uDFA8 Select project preset",
26536
28020
  options: [
26537
28021
  {
26538
28022
  value: "minimal",
26539
28023
  label: "\u26A1 Minimal",
26540
- hint: "Single file, clean start - perfect for learning Bun"
28024
+ hint: "Single-file project, clean start - perfect for CLIs and scripts"
26541
28025
  },
26542
28026
  {
26543
28027
  value: "web",
26544
- label: "\uD83C\uDF10 Web App",
26545
- hint: "Next.js 16 + React 19 - full-stack web application"
28028
+ label: "\uD83C\uDF10 Web Application",
28029
+ hint: "Next.js 16 + React 19 + Tailwind CSS 4 - production-ready web app"
26546
28030
  },
26547
28031
  {
26548
28032
  value: "api",
26549
28033
  label: "\uD83D\uDE80 API Server",
26550
- hint: "Hono + Bun.serve() - ultra-fast REST API"
28034
+ hint: "Hono 4 + Bun.serve() - ultra-fast REST API with native HMR"
26551
28035
  },
26552
28036
  {
26553
28037
  value: "full",
26554
28038
  label: "\uD83D\uDCE6 Full-Stack Monorepo",
26555
- hint: "Web + Platform + API - enterprise SaaS setup"
28039
+ hint: "Web + API + shared packages - enterprise-grade SaaS architecture"
26556
28040
  }
26557
28041
  ]
26558
28042
  });
@@ -26565,27 +28049,32 @@ async function enhancedInitCommand(options = {}) {
26565
28049
  if (!database && (preset === "api" || preset === "full")) {
26566
28050
  if (!isNonInteractive) {
26567
28051
  database = await ve({
26568
- message: "\uD83D\uDDC4\uFE0F Database setup?",
28052
+ message: "\uD83D\uDDC4\uFE0F Database configuration",
26569
28053
  options: [
26570
28054
  {
26571
28055
  value: "postgres-drizzle",
26572
28056
  label: "PostgreSQL + Drizzle ORM",
26573
- hint: "Production-ready, type-safe SQL database"
28057
+ hint: "Production-ready PostgreSQL with type-safe Drizzle ORM queries"
26574
28058
  },
26575
28059
  {
26576
28060
  value: "supabase",
26577
- label: "Supabase",
26578
- hint: "PostgreSQL + Auth + Storage + Realtime - all-in-one"
28061
+ label: "Supabase (Client Only)",
28062
+ hint: "Supabase JS client only - Auth, Storage, Realtime without Drizzle ORM"
28063
+ },
28064
+ {
28065
+ value: "supabase-drizzle",
28066
+ label: "Supabase + Drizzle ORM",
28067
+ hint: "Full Supabase stack with Drizzle ORM for type-safe database queries"
26579
28068
  },
26580
28069
  {
26581
28070
  value: "sqlite-drizzle",
26582
28071
  label: "SQLite + Drizzle ORM",
26583
- hint: "Local-first, embedded database - perfect for prototypes"
28072
+ hint: "Local-first embedded database - perfect for prototypes and local development"
26584
28073
  },
26585
28074
  {
26586
28075
  value: "none",
26587
28076
  label: "None",
26588
- hint: "I'll add it later"
28077
+ hint: "Skip database setup - add later if needed"
26589
28078
  }
26590
28079
  ]
26591
28080
  });
@@ -26597,21 +28086,116 @@ async function enhancedInitCommand(options = {}) {
26597
28086
  database = "none";
26598
28087
  }
26599
28088
  }
28089
+ let supabasePreset;
28090
+ let supabaseFeatures;
28091
+ let supabaseWithDrizzle;
28092
+ if (database === "supabase" || database === "supabase-drizzle") {
28093
+ supabaseWithDrizzle = database === "supabase-drizzle";
28094
+ const presetEnv = process.env.BUNKIT_SUPABASE_PRESET;
28095
+ supabasePreset = presetEnv || options.supabasePreset;
28096
+ if (!supabasePreset && !isNonInteractive) {
28097
+ supabasePreset = await ve({
28098
+ message: "\uD83C\uDFAF Supabase configuration preset",
28099
+ options: [
28100
+ {
28101
+ value: "full-stack",
28102
+ label: "Full Stack (Recommended)",
28103
+ hint: "Complete Supabase setup - Auth, Storage, Realtime, and Database"
28104
+ },
28105
+ {
28106
+ value: "auth-only",
28107
+ label: "Auth Only",
28108
+ hint: "Authentication only - perfect for simple apps with external data"
28109
+ },
28110
+ {
28111
+ value: "database-only",
28112
+ label: "Database Only",
28113
+ hint: "PostgreSQL database access only - no Auth, Storage, or Realtime"
28114
+ },
28115
+ {
28116
+ value: "custom",
28117
+ label: "Custom",
28118
+ hint: "Manually select Supabase features to include"
28119
+ }
28120
+ ]
28121
+ });
28122
+ if (pD(supabasePreset)) {
28123
+ xe("Operation cancelled.");
28124
+ process.exit(0);
28125
+ }
28126
+ } else if (!supabasePreset) {
28127
+ supabasePreset = "full-stack";
28128
+ }
28129
+ if (supabasePreset === "full-stack") {
28130
+ supabaseFeatures = ["auth", "storage", "realtime", "database"];
28131
+ } else if (supabasePreset === "auth-only") {
28132
+ supabaseFeatures = ["auth"];
28133
+ } else if (supabasePreset === "database-only") {
28134
+ supabaseFeatures = ["database"];
28135
+ } else {
28136
+ const availableFeaturesEnv = process.env.BUNKIT_SUPABASE_FEATURES;
28137
+ let availableFeatures;
28138
+ if (availableFeaturesEnv) {
28139
+ availableFeatures = availableFeaturesEnv.split(",").map((f) => f.trim());
28140
+ } else if (options.supabaseFeatures) {
28141
+ availableFeatures = Array.isArray(options.supabaseFeatures) ? options.supabaseFeatures : String(options.supabaseFeatures).split(",").map((f) => f.trim());
28142
+ }
28143
+ if (!availableFeatures && !isNonInteractive) {
28144
+ const selectedFeatures = await fe({
28145
+ message: "\u2728 Select Supabase features to include",
28146
+ options: [
28147
+ {
28148
+ value: "auth",
28149
+ label: "Authentication",
28150
+ hint: "User authentication and authorization (sign up, sign in, sessions)"
28151
+ },
28152
+ {
28153
+ value: "storage",
28154
+ label: "Storage",
28155
+ hint: "File storage and CDN for images, documents, and media"
28156
+ },
28157
+ {
28158
+ value: "realtime",
28159
+ label: "Realtime",
28160
+ hint: "Real-time subscriptions and live updates via WebSockets"
28161
+ },
28162
+ {
28163
+ value: "edge-functions",
28164
+ label: "Edge Functions",
28165
+ hint: "Serverless functions deployed at the edge for low latency"
28166
+ },
28167
+ {
28168
+ value: "database",
28169
+ label: "Database",
28170
+ hint: "PostgreSQL database access via Supabase client"
28171
+ }
28172
+ ]
28173
+ });
28174
+ if (pD(selectedFeatures)) {
28175
+ xe("Operation cancelled.");
28176
+ process.exit(0);
28177
+ }
28178
+ supabaseFeatures = selectedFeatures.length > 0 ? selectedFeatures : ["auth", "database"];
28179
+ } else {
28180
+ supabaseFeatures = availableFeatures || ["auth", "database"];
28181
+ }
28182
+ }
28183
+ }
26600
28184
  let codeQuality = getOptionValue("BUNKIT_CODE_QUALITY", options.codeQuality, "ultracite");
26601
28185
  if (!codeQuality) {
26602
28186
  if (!isNonInteractive) {
26603
28187
  codeQuality = await ve({
26604
- message: "\uD83E\uDD16 Code quality setup?",
28188
+ message: "\uD83E\uDD16 Code quality tool",
26605
28189
  options: [
26606
28190
  {
26607
28191
  value: "ultracite",
26608
28192
  label: "Ultracite (Recommended)",
26609
- hint: "AI-optimized Biome preset - syncs rules for Cursor, Claude, Windsurf"
28193
+ hint: "AI-optimized Biome preset - syncs rules for Cursor, Claude Code, Windsurf, Zed"
26610
28194
  },
26611
28195
  {
26612
28196
  value: "biome",
26613
28197
  label: "Biome",
26614
- hint: "Standard Biome with good defaults - fast and reliable"
28198
+ hint: "Standard Biome configuration - fast, reliable, zero-config linting and formatting"
26615
28199
  }
26616
28200
  ]
26617
28201
  });
@@ -26627,22 +28211,22 @@ async function enhancedInitCommand(options = {}) {
26627
28211
  if (!tsStrictness) {
26628
28212
  if (!isNonInteractive) {
26629
28213
  tsStrictness = await ve({
26630
- message: "\uD83D\uDD12 TypeScript strictness?",
28214
+ message: "\uD83D\uDD12 TypeScript strictness level",
26631
28215
  options: [
26632
28216
  {
26633
28217
  value: "strict",
26634
28218
  label: "Strict (Recommended)",
26635
- hint: "Maximum type safety - catches bugs early, prevents headaches"
28219
+ hint: "Maximum type safety - catches bugs early, prevents runtime errors"
26636
28220
  },
26637
28221
  {
26638
28222
  value: "moderate",
26639
28223
  label: "Moderate",
26640
- hint: "Balanced - good safety without being too rigid"
28224
+ hint: "Balanced type checking - good safety without excessive strictness"
26641
28225
  },
26642
28226
  {
26643
28227
  value: "loose",
26644
28228
  label: "Loose",
26645
- hint: "Minimal checks - quick prototyping, migrate from JavaScript"
28229
+ hint: "Minimal type checking - quick prototyping, easier migration from JavaScript"
26646
28230
  }
26647
28231
  ]
26648
28232
  });
@@ -26658,22 +28242,22 @@ async function enhancedInitCommand(options = {}) {
26658
28242
  if (!cssFramework && (preset === "web" || preset === "full")) {
26659
28243
  if (!isNonInteractive) {
26660
28244
  cssFramework = await ve({
26661
- message: "\uD83C\uDFA8 CSS framework?",
28245
+ message: "\uD83C\uDFA8 CSS framework",
26662
28246
  options: [
26663
28247
  {
26664
28248
  value: "tailwind",
26665
28249
  label: "Tailwind CSS 4 (Recommended)",
26666
- hint: "Utility-first, fast, modern - with OKLCH colors and @theme"
28250
+ hint: "Utility-first CSS framework - fast, modern, with OKLCH colors and @theme"
26667
28251
  },
26668
28252
  {
26669
28253
  value: "vanilla",
26670
28254
  label: "Vanilla CSS",
26671
- hint: "Plain CSS files - full control, no framework"
28255
+ hint: "Plain CSS files - full control, no framework dependencies"
26672
28256
  },
26673
28257
  {
26674
28258
  value: "css-modules",
26675
28259
  label: "CSS Modules",
26676
- hint: "Scoped CSS - automatic class name generation"
28260
+ hint: "Scoped CSS with automatic class name generation - prevents style conflicts"
26677
28261
  }
26678
28262
  ]
26679
28263
  });
@@ -26689,17 +28273,17 @@ async function enhancedInitCommand(options = {}) {
26689
28273
  if (!uiLibrary && (preset === "web" || preset === "full") && cssFramework === "tailwind") {
26690
28274
  if (!isNonInteractive) {
26691
28275
  uiLibrary = await ve({
26692
- message: "\uD83E\uDDE9 UI component library?",
28276
+ message: "\uD83E\uDDE9 UI component library",
26693
28277
  options: [
26694
28278
  {
26695
28279
  value: "shadcn",
26696
28280
  label: "shadcn/ui (Recommended)",
26697
- hint: "64+ components, accessible, customizable - production-ready"
28281
+ hint: "64+ accessible components, fully customizable, production-ready"
26698
28282
  },
26699
28283
  {
26700
28284
  value: "none",
26701
28285
  label: "None",
26702
- hint: "I'll build my own components"
28286
+ hint: "Skip UI library - build custom components or add later"
26703
28287
  }
26704
28288
  ]
26705
28289
  });
@@ -26711,26 +28295,118 @@ async function enhancedInitCommand(options = {}) {
26711
28295
  uiLibrary = "shadcn";
26712
28296
  }
26713
28297
  }
28298
+ let shadcnStyle = getOptionValue("BUNKIT_SHADCN_STYLE", options.shadcnStyle);
28299
+ if (!shadcnStyle && uiLibrary === "shadcn") {
28300
+ if (!isNonInteractive) {
28301
+ shadcnStyle = await ve({
28302
+ message: "\uD83C\uDFA8 shadcn/ui component style",
28303
+ options: [
28304
+ {
28305
+ value: "new-york",
28306
+ label: "New York (Recommended)",
28307
+ hint: "Modern design aesthetic - rounded corners, subtle shadows, clean look"
28308
+ },
28309
+ {
28310
+ value: "default",
28311
+ label: "Default",
28312
+ hint: "Classic design aesthetic - sharper edges, higher contrast, traditional look"
28313
+ }
28314
+ ]
28315
+ });
28316
+ if (pD(shadcnStyle)) {
28317
+ xe("Operation cancelled.");
28318
+ process.exit(0);
28319
+ }
28320
+ } else {
28321
+ shadcnStyle = "new-york";
28322
+ }
28323
+ }
28324
+ let shadcnBaseColor = getOptionValue("BUNKIT_SHADCN_BASE_COLOR", options.shadcnBaseColor);
28325
+ if (!shadcnBaseColor && uiLibrary === "shadcn") {
28326
+ if (!isNonInteractive) {
28327
+ shadcnBaseColor = await ve({
28328
+ message: "\uD83C\uDFA8 shadcn/ui base color theme",
28329
+ options: [
28330
+ {
28331
+ value: "zinc",
28332
+ label: "Zinc (Recommended)",
28333
+ hint: "Neutral gray palette - versatile, modern, works with any accent color"
28334
+ },
28335
+ {
28336
+ value: "neutral",
28337
+ label: "Neutral",
28338
+ hint: "Pure neutral palette - no color cast, perfect grayscale"
28339
+ },
28340
+ {
28341
+ value: "gray",
28342
+ label: "Gray",
28343
+ hint: "Warm gray palette - slightly warmer tone than zinc"
28344
+ },
28345
+ {
28346
+ value: "slate",
28347
+ label: "Slate",
28348
+ hint: "Cool gray palette - slightly bluer tone, modern and crisp"
28349
+ },
28350
+ {
28351
+ value: "stone",
28352
+ label: "Stone",
28353
+ hint: "Warm beige-gray palette - earthy, natural, organic feel"
28354
+ }
28355
+ ]
28356
+ });
28357
+ if (pD(shadcnBaseColor)) {
28358
+ xe("Operation cancelled.");
28359
+ process.exit(0);
28360
+ }
28361
+ } else {
28362
+ shadcnBaseColor = "zinc";
28363
+ }
28364
+ }
28365
+ let shadcnRadius = getOptionValue("BUNKIT_SHADCN_RADIUS", options.shadcnRadius);
28366
+ if (!shadcnRadius && uiLibrary === "shadcn") {
28367
+ if (!isNonInteractive) {
28368
+ const radiusInput = await he({
28369
+ message: "\uD83D\uDCD0 Component border radius",
28370
+ placeholder: "0.625rem (default)",
28371
+ initialValue: "0.625rem",
28372
+ validate: (value) => {
28373
+ if (!value.trim()) {
28374
+ return "Radius cannot be empty";
28375
+ }
28376
+ if (!/^\d+(\.\d+)?(rem|px|em|%)$/.test(value.trim())) {
28377
+ return "Please enter a valid CSS value (e.g., 0.5rem, 8px)";
28378
+ }
28379
+ }
28380
+ });
28381
+ if (pD(radiusInput)) {
28382
+ xe("Operation cancelled.");
28383
+ process.exit(0);
28384
+ }
28385
+ shadcnRadius = radiusInput;
28386
+ } else {
28387
+ shadcnRadius = "0.625rem";
28388
+ }
28389
+ }
26714
28390
  let testing = getOptionValue("BUNKIT_TESTING", options.testing, "bun-test");
26715
28391
  if (!testing) {
26716
28392
  if (!isNonInteractive) {
26717
28393
  testing = await ve({
26718
- message: "\uD83E\uDDEA Testing framework?",
28394
+ message: "\uD83E\uDDEA Testing framework",
26719
28395
  options: [
26720
28396
  {
26721
28397
  value: "bun-test",
26722
28398
  label: "Bun Test (Recommended)",
26723
- hint: "Built-in, fast, Jest-compatible - no extra dependencies"
28399
+ hint: "Built-in testing framework - fast, Jest-compatible, zero configuration"
26724
28400
  },
26725
28401
  {
26726
28402
  value: "vitest",
26727
28403
  label: "Vitest",
26728
- hint: "Vite-powered, fast, ESM-first - popular in ecosystem"
28404
+ hint: "Vite-powered testing framework - fast, ESM-first, popular ecosystem choice"
26729
28405
  },
26730
28406
  {
26731
28407
  value: "none",
26732
28408
  label: "None",
26733
- hint: "I'll add testing later"
28409
+ hint: "Skip testing setup - add testing framework later if needed"
26734
28410
  }
26735
28411
  ]
26736
28412
  });
@@ -26746,7 +28422,7 @@ async function enhancedInitCommand(options = {}) {
26746
28422
  if (docker === undefined) {
26747
28423
  if (!isNonInteractive) {
26748
28424
  docker = await ye({
26749
- message: "\uD83D\uDC33 Add Docker configuration?",
28425
+ message: "\uD83D\uDC33 Include Docker configuration",
26750
28426
  initialValue: false
26751
28427
  });
26752
28428
  if (pD(docker)) {
@@ -26761,7 +28437,7 @@ async function enhancedInitCommand(options = {}) {
26761
28437
  if (cicd === undefined) {
26762
28438
  if (!isNonInteractive) {
26763
28439
  cicd = await ye({
26764
- message: "\u2699\uFE0F Add GitHub Actions CI/CD?",
28440
+ message: "\u2699\uFE0F Include GitHub Actions CI/CD workflow",
26765
28441
  initialValue: false
26766
28442
  });
26767
28443
  if (pD(cicd)) {
@@ -26776,7 +28452,7 @@ async function enhancedInitCommand(options = {}) {
26776
28452
  if (shouldInstall === undefined) {
26777
28453
  if (!isNonInteractive) {
26778
28454
  shouldInstall = await ye({
26779
- message: "\uD83D\uDCE5 Install dependencies?",
28455
+ message: "\uD83D\uDCE5 Install dependencies after project creation",
26780
28456
  initialValue: true
26781
28457
  });
26782
28458
  if (pD(shouldInstall)) {
@@ -26791,7 +28467,7 @@ async function enhancedInitCommand(options = {}) {
26791
28467
  if (shouldInitGit === undefined) {
26792
28468
  if (!isNonInteractive) {
26793
28469
  shouldInitGit = await ye({
26794
- message: "\uD83D\uDD27 Initialize git repository?",
28470
+ message: "\uD83D\uDD27 Initialize Git repository",
26795
28471
  initialValue: true
26796
28472
  });
26797
28473
  if (pD(shouldInitGit)) {
@@ -26803,28 +28479,56 @@ async function enhancedInitCommand(options = {}) {
26803
28479
  }
26804
28480
  }
26805
28481
  if (!isNonInteractive) {
26806
- console.log(`
26807
- ` + boxen([
26808
- `${source_default.bold("Project:")} ${source_default.cyan(projectName)}`,
28482
+ const configSummary = [
28483
+ "",
28484
+ `${source_default.bold.cyan("\uD83D\uDCE6 Project Configuration")}`,
28485
+ `${source_default.dim("\u2500".repeat(40))}`,
28486
+ `${source_default.bold("Project Name:")} ${source_default.cyan(projectName)}`,
26809
28487
  `${source_default.bold("Preset:")} ${source_default.cyan(preset)}`,
26810
- database ? `${source_default.bold("Database:")} ${source_default.cyan(database)}` : "",
26811
- `${source_default.bold("Code Quality:")} ${source_default.cyan(codeQuality)}`,
26812
- `${source_default.bold("TypeScript:")} ${source_default.cyan(tsStrictness)}`,
26813
- cssFramework ? `${source_default.bold("CSS:")} ${source_default.cyan(cssFramework)}` : "",
26814
- uiLibrary ? `${source_default.bold("UI Library:")} ${source_default.cyan(uiLibrary)}` : "",
26815
- `${source_default.bold("Testing:")} ${source_default.cyan(testing)}`,
26816
- docker ? `${source_default.bold("Docker:")} ${source_default.green("\u2713")}` : "",
26817
- cicd ? `${source_default.bold("CI/CD:")} ${source_default.green("\u2713")}` : ""
28488
+ "",
28489
+ database && database !== "none" ? [
28490
+ `${source_default.bold.yellow("\uD83D\uDDC4\uFE0F Database")}`,
28491
+ ` ${source_default.bold("Type:")} ${source_default.cyan(database)}`,
28492
+ (database === "supabase" || database === "supabase-drizzle") && supabasePreset ? ` ${source_default.bold("Preset:")} ${source_default.cyan(supabasePreset)}` : "",
28493
+ (database === "supabase" || database === "supabase-drizzle") && supabaseFeatures ? ` ${source_default.bold("Features:")} ${source_default.cyan(supabaseFeatures.join(", "))}` : ""
28494
+ ].filter(Boolean).join(`
28495
+ `) : "",
28496
+ "",
28497
+ `${source_default.bold.yellow("\uD83D\uDEE0\uFE0F Development Tools")}`,
28498
+ ` ${source_default.bold("Code Quality:")} ${source_default.cyan(codeQuality)}`,
28499
+ ` ${source_default.bold("TypeScript:")} ${source_default.cyan(tsStrictness)}`,
28500
+ ` ${source_default.bold("Testing:")} ${source_default.cyan(testing)}`,
28501
+ "",
28502
+ cssFramework ? [
28503
+ `${source_default.bold.yellow("\uD83C\uDFA8 Styling")}`,
28504
+ ` ${source_default.bold("CSS Framework:")} ${source_default.cyan(cssFramework)}`,
28505
+ uiLibrary ? ` ${source_default.bold("UI Library:")} ${source_default.cyan(uiLibrary)}` : "",
28506
+ uiLibrary === "shadcn" && shadcnStyle ? ` ${source_default.bold(" Style:")} ${source_default.cyan(shadcnStyle)}` : "",
28507
+ uiLibrary === "shadcn" && shadcnBaseColor ? ` ${source_default.bold(" Base Color:")} ${source_default.cyan(shadcnBaseColor)}` : "",
28508
+ uiLibrary === "shadcn" && shadcnRadius ? ` ${source_default.bold(" Radius:")} ${source_default.cyan(shadcnRadius)}` : ""
28509
+ ].filter(Boolean).join(`
28510
+ `) : "",
28511
+ "",
28512
+ docker || cicd ? [
28513
+ `${source_default.bold.yellow("\uD83D\uDE80 Deployment")}`,
28514
+ docker ? ` ${source_default.bold("Docker:")} ${source_default.green("\u2713 Enabled")}` : "",
28515
+ cicd ? ` ${source_default.bold("CI/CD:")} ${source_default.green("\u2713 Enabled")}` : ""
28516
+ ].filter(Boolean).join(`
28517
+ `) : "",
28518
+ ""
26818
28519
  ].filter(Boolean).join(`
26819
- `), {
26820
- padding: 1,
26821
- title: "\uD83D\uDCCB Configuration",
28520
+ `);
28521
+ console.log(`
28522
+ ` + boxen(configSummary, {
28523
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28524
+ title: "\uD83D\uDCCB Configuration Summary",
26822
28525
  titleAlignment: "left",
26823
28526
  borderColor: "cyan",
26824
- borderStyle: "round"
28527
+ borderStyle: "round",
28528
+ dimBorder: false
26825
28529
  }));
26826
28530
  const confirm = await ye({
26827
- message: "Proceed with this configuration?",
28531
+ message: "Confirm project configuration",
26828
28532
  initialValue: true
26829
28533
  });
26830
28534
  if (pD(confirm) || !confirm) {
@@ -26832,8 +28536,9 @@ async function enhancedInitCommand(options = {}) {
26832
28536
  process.exit(0);
26833
28537
  }
26834
28538
  }
28539
+ console.log("");
26835
28540
  const s = Y2();
26836
- s.start("\uD83D\uDD28 Creating project structure...");
28541
+ s.start(`${source_default.cyan("\uD83D\uDD28")} Creating project structure...`);
26837
28542
  try {
26838
28543
  const config = {
26839
28544
  name: projectName,
@@ -26850,12 +28555,18 @@ async function enhancedInitCommand(options = {}) {
26850
28555
  docker,
26851
28556
  cicd,
26852
28557
  envExample: true,
26853
- pathAliases: true
28558
+ pathAliases: true,
28559
+ shadcnStyle,
28560
+ shadcnBaseColor,
28561
+ shadcnRadius,
28562
+ supabasePreset,
28563
+ supabaseFeatures,
28564
+ supabaseWithDrizzle
26854
28565
  };
26855
28566
  await createProject(config);
26856
28567
  const projectPath = join(process.cwd(), config.path);
26857
28568
  const context = createTemplateContext(config);
26858
- s.message("\uD83D\uDCDD Generating files...");
28569
+ s.message(`${source_default.cyan("\uD83D\uDCDD")} Generating project files...`);
26859
28570
  switch (preset) {
26860
28571
  case "minimal":
26861
28572
  await buildMinimalPreset(projectPath, context);
@@ -26871,18 +28582,22 @@ async function enhancedInitCommand(options = {}) {
26871
28582
  break;
26872
28583
  }
26873
28584
  if (database && database !== "none") {
26874
- s.message(`\uD83D\uDDC4\uFE0F Setting up ${database}...`);
28585
+ const dbName = database === "postgres-drizzle" ? "PostgreSQL + Drizzle ORM" : database === "supabase" ? "Supabase (Client Only)" : database === "supabase-drizzle" ? "Supabase + Drizzle ORM" : database === "sqlite-drizzle" ? "SQLite + Drizzle ORM" : database;
28586
+ s.message(`${source_default.cyan("\uD83D\uDDC4\uFE0F")} Configuring ${dbName}...`);
28587
+ }
28588
+ if (uiLibrary === "shadcn") {
28589
+ s.message(`${source_default.cyan("\uD83C\uDFA8")} Setting up shadcn/ui components...`);
26875
28590
  }
26876
28591
  if (codeQuality === "ultracite") {
26877
- s.message("\uD83E\uDD16 Configuring Ultracite for AI editors...");
28592
+ s.message(`${source_default.cyan("\uD83E\uDD16")} Configuring Ultracite for AI editors...`);
26878
28593
  }
26879
28594
  if (docker) {
26880
- s.message("\uD83D\uDC33 Adding Docker configuration...");
28595
+ s.message(`${source_default.cyan("\uD83D\uDC33")} Adding Docker configuration...`);
26881
28596
  }
26882
28597
  if (cicd) {
26883
- s.message("\u2699\uFE0F Adding GitHub Actions...");
28598
+ s.message(`${source_default.cyan("\u2699\uFE0F")} Adding GitHub Actions CI/CD workflow...`);
26884
28599
  }
26885
- s.stop("\u2705 Project created!");
28600
+ s.stop(`${source_default.green("\u2705")} Project structure created successfully!`);
26886
28601
  if (shouldInstall && preset !== "full") {
26887
28602
  const additionalDeps = {};
26888
28603
  if (database && database !== "none") {
@@ -26908,28 +28623,121 @@ async function enhancedInitCommand(options = {}) {
26908
28623
  } else if (shouldInstall && preset === "full") {
26909
28624
  await installDependencies(projectPath);
26910
28625
  }
28626
+ if (shouldInstall && uiLibrary === "shadcn" && (preset === "web" || preset === "full")) {
28627
+ const componentSpinner = Y2();
28628
+ componentSpinner.start(`${source_default.cyan("\uD83E\uDDE9")} Installing default shadcn/ui components (button, card)...`);
28629
+ try {
28630
+ if (preset === "full") {
28631
+ await installDefaultShadcnComponents(join(projectPath, "packages/ui"), {
28632
+ silent: true
28633
+ });
28634
+ } else {
28635
+ await installDefaultShadcnComponents(projectPath, {
28636
+ silent: true
28637
+ });
28638
+ }
28639
+ componentSpinner.stop(`${source_default.green("\u2705")} Default components installed`);
28640
+ } catch (error) {
28641
+ componentSpinner.stop(`${source_default.yellow("\u26A0\uFE0F")} Could not install automatically`);
28642
+ Me("Install manually: bunx shadcn@latest add button card", "Component Installation");
28643
+ }
28644
+ }
26911
28645
  const getDevCommand = () => {
26912
28646
  if (preset === "full" || preset === "web")
26913
28647
  return "bun dev";
26914
28648
  return "bun run dev";
26915
28649
  };
26916
- const nextSteps = [
26917
- `${source_default.cyan("cd")} ${projectName}`,
26918
- shouldInstall ? "" : `${source_default.cyan("bun install")}`,
26919
- `${source_default.cyan(getDevCommand())} ${source_default.dim("# Start development")}`
28650
+ const getPresetEmoji = () => {
28651
+ switch (preset) {
28652
+ case "minimal":
28653
+ return "\u26A1";
28654
+ case "web":
28655
+ return "\uD83C\uDF10";
28656
+ case "api":
28657
+ return "\uD83D\uDE80";
28658
+ case "full":
28659
+ return "\uD83D\uDCE6";
28660
+ default:
28661
+ return "\u2728";
28662
+ }
28663
+ };
28664
+ const nextStepsContent = [
28665
+ `${source_default.bold.cyan("\uD83D\uDCC1 Navigate to your project")}`,
28666
+ `${source_default.cyan("cd")} ${source_default.bold(projectName)}`,
28667
+ "",
28668
+ shouldInstall ? "" : [
28669
+ `${source_default.bold.cyan("\uD83D\uDCE6 Install dependencies")}`,
28670
+ `${source_default.cyan("bun install")}`,
28671
+ ""
28672
+ ].join(`
28673
+ `),
28674
+ `${source_default.bold.cyan("\uD83D\uDE80 Start development")}`,
28675
+ `${source_default.cyan(getDevCommand())} ${source_default.dim("# Start development server")}`,
28676
+ "",
28677
+ `${source_default.dim("\u2500".repeat(40))}`,
28678
+ `${source_default.bold.yellow("\uD83D\uDCA1 Quick Tips")}`,
28679
+ "",
28680
+ database && database !== "none" ? ` ${source_default.dim("\u2022")} Configure your database connection in ${source_default.cyan(".env")}` : "",
28681
+ uiLibrary === "shadcn" ? ` ${source_default.dim("\u2022")} Add more components: ${source_default.cyan("bunkit add component --all")}` : "",
28682
+ preset === "full" ? ` ${source_default.dim("\u2022")} Add workspaces: ${source_default.cyan("bunkit add workspace")}` : "",
28683
+ preset === "full" ? ` ${source_default.dim("\u2022")} Add packages: ${source_default.cyan("bunkit add package")}` : "",
28684
+ ` ${source_default.dim("\u2022")} Read the ${source_default.cyan("README.md")} for project-specific documentation`,
28685
+ database === "supabase" || database === "supabase-drizzle" ? ` ${source_default.dim("\u2022")} Check ${source_default.cyan("SHADCN.md")} for shadcn/ui usage guide` : ""
26920
28686
  ].filter(Boolean).join(`
26921
28687
  `);
26922
28688
  console.log(`
26923
- ` + boxen(nextSteps, {
26924
- padding: 1,
26925
- title: "\uD83D\uDE80 Next steps",
28689
+ ` + boxen(nextStepsContent, {
28690
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28691
+ title: `${getPresetEmoji()} Next Steps`,
26926
28692
  titleAlignment: "left",
26927
28693
  borderColor: "green",
26928
- borderStyle: "round"
28694
+ borderStyle: "round",
28695
+ dimBorder: false
28696
+ }));
28697
+ const projectSummary = [
28698
+ `${source_default.bold.green("\u2728 Project created successfully!")}`,
28699
+ "",
28700
+ `${source_default.dim("Project location:")} ${source_default.cyan(join(process.cwd(), projectName))}`,
28701
+ `${source_default.dim("Preset:")} ${source_default.cyan(preset)}`,
28702
+ database && database !== "none" ? `${source_default.dim("Database:")} ${source_default.cyan(database)}` : "",
28703
+ uiLibrary ? `${source_default.dim("UI Library:")} ${source_default.cyan(uiLibrary)}` : "",
28704
+ "",
28705
+ `${source_default.dim("Happy coding! \uD83C\uDF89")}`
28706
+ ].filter(Boolean).join(`
28707
+ `);
28708
+ console.log(`
28709
+ ` + boxen(projectSummary, {
28710
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28711
+ borderColor: "green",
28712
+ borderStyle: "round",
28713
+ dimBorder: true
26929
28714
  }));
26930
28715
  } catch (error) {
26931
- s.stop("\u274C Failed to create project");
26932
- xe(`${import_picocolors4.default.red("Error:")} ${error.message}`);
28716
+ s.stop(`${source_default.red("\u274C")} Failed to create project`);
28717
+ const errorMessage = error.message;
28718
+ const errorBox = [
28719
+ `${source_default.bold.red("Error occurred during project creation")}`,
28720
+ "",
28721
+ source_default.red(errorMessage),
28722
+ "",
28723
+ `${source_default.dim("\u2500".repeat(40))}`,
28724
+ `${source_default.bold.yellow("\uD83D\uDCA1 Troubleshooting Tips")}`,
28725
+ "",
28726
+ ` ${source_default.dim("\u2022")} Check if the directory already exists`,
28727
+ ` ${source_default.dim("\u2022")} Ensure you have write permissions`,
28728
+ ` ${source_default.dim("\u2022")} Verify your internet connection (for dependency installation)`,
28729
+ ` ${source_default.dim("\u2022")} Try running with ${source_default.cyan("--no-install")} to skip dependency installation`,
28730
+ "",
28731
+ `${source_default.dim("Need help?")} ${source_default.cyan("https://github.com/Arakiss/bunkit/issues")}`
28732
+ ].join(`
28733
+ `);
28734
+ console.log(`
28735
+ ` + boxen(errorBox, {
28736
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28737
+ borderColor: "red",
28738
+ borderStyle: "round"
28739
+ }));
28740
+ xe("Operation cancelled due to error");
26933
28741
  process.exit(1);
26934
28742
  }
26935
28743
  }
@@ -26948,8 +28756,9 @@ async function createCommand2(preset, name, options) {
26948
28756
  if (!validation2.valid) {
26949
28757
  throw new Error(`Invalid project name: ${validation2.error}`);
26950
28758
  }
28759
+ console.log("");
26951
28760
  const s = Y2();
26952
- s.start(`Creating ${preset} project: ${name}`);
28761
+ s.start(`${source_default.cyan("\uD83D\uDD28")} Creating ${preset} project: ${source_default.bold(name)}`);
26953
28762
  try {
26954
28763
  const config = {
26955
28764
  name,
@@ -26966,11 +28775,11 @@ async function createCommand2(preset, name, options) {
26966
28775
  envExample: true,
26967
28776
  pathAliases: true
26968
28777
  };
26969
- s.message("\uD83D\uDD28 Creating project structure...");
28778
+ s.message(`${source_default.cyan("\uD83D\uDCC1")} Creating project structure...`);
26970
28779
  await createProject(config);
26971
28780
  const projectPath = join(process.cwd(), config.path);
26972
28781
  const context = createTemplateContext(config);
26973
- s.message("\uD83D\uDCDD Generating files...");
28782
+ s.message(`${source_default.cyan("\uD83D\uDCDD")} Generating project files...`);
26974
28783
  switch (preset) {
26975
28784
  case "minimal":
26976
28785
  await buildMinimalPreset(projectPath, context);
@@ -26985,22 +28794,65 @@ async function createCommand2(preset, name, options) {
26985
28794
  await buildFullPreset(projectPath, context);
26986
28795
  break;
26987
28796
  }
26988
- s.stop(`Project ${name} created!`);
26989
- const nextSteps = [
26990
- `${source_default.cyan("cd")} ${name}`,
26991
- source_default.cyan(preset === "web" ? "bun dev" : "bun run dev")
26992
- ].join(`
28797
+ s.message(`${source_default.cyan("\u2728")} Finalizing setup...`);
28798
+ s.stop(`${source_default.green("\u2705")} Project ${source_default.bold(name)} created successfully!`);
28799
+ const getPresetEmoji = () => {
28800
+ switch (preset) {
28801
+ case "minimal":
28802
+ return "\u26A1";
28803
+ case "web":
28804
+ return "\uD83C\uDF10";
28805
+ case "api":
28806
+ return "\uD83D\uDE80";
28807
+ case "full":
28808
+ return "\uD83D\uDCE6";
28809
+ default:
28810
+ return "\u2728";
28811
+ }
28812
+ };
28813
+ const nextStepsContent = [
28814
+ `${source_default.bold.cyan("\uD83D\uDCC1 Navigate to your project")}`,
28815
+ `${source_default.cyan("cd")} ${source_default.bold(name)}`,
28816
+ "",
28817
+ options.install === false ? [
28818
+ `${source_default.bold.cyan("\uD83D\uDCE6 Install dependencies")}`,
28819
+ `${source_default.cyan("bun install")}`,
28820
+ ""
28821
+ ].join(`
28822
+ `) : "",
28823
+ `${source_default.bold.cyan("\uD83D\uDE80 Start development")}`,
28824
+ `${source_default.cyan(preset === "web" ? "bun dev" : "bun run dev")} ${source_default.dim("# Start development server")}`,
28825
+ "",
28826
+ `${source_default.dim("\u2500".repeat(40))}`,
28827
+ `${source_default.bold.yellow("\uD83D\uDCA1 Tip")}`,
28828
+ ` Use ${source_default.cyan("bunkit init")} for full customization options`
28829
+ ].filter(Boolean).join(`
26993
28830
  `);
26994
28831
  console.log(`
26995
- ` + boxen(nextSteps, {
26996
- padding: 1,
26997
- title: "\uD83D\uDCCB Next steps",
28832
+ ` + boxen(nextStepsContent, {
28833
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28834
+ title: `${getPresetEmoji()} Next Steps`,
26998
28835
  titleAlignment: "left",
26999
- borderColor: "cyan",
27000
- borderStyle: "round"
28836
+ borderColor: "green",
28837
+ borderStyle: "round",
28838
+ dimBorder: false
27001
28839
  }));
27002
28840
  } catch (error) {
27003
- s.stop("\u274C Project creation failed");
28841
+ s.stop(`${source_default.red("\u274C")} Project creation failed`);
28842
+ const errorBox = [
28843
+ `${source_default.bold.red("Error occurred")}`,
28844
+ "",
28845
+ source_default.red(error.message),
28846
+ "",
28847
+ `${source_default.dim("Need help?")} ${source_default.cyan("https://github.com/Arakiss/bunkit/issues")}`
28848
+ ].join(`
28849
+ `);
28850
+ console.log(`
28851
+ ` + boxen(errorBox, {
28852
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
28853
+ borderColor: "red",
28854
+ borderStyle: "round"
28855
+ }));
27004
28856
  throw error;
27005
28857
  }
27006
28858
  }
@@ -27008,7 +28860,7 @@ async function createCommand2(preset, name, options) {
27008
28860
  // src/commands/add/workspace.ts
27009
28861
  init_dist();
27010
28862
  init_src();
27011
- var import_picocolors5 = __toESM(require_picocolors(), 1);
28863
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
27012
28864
  function getWorkspaceDependencies(preset) {
27013
28865
  switch (preset) {
27014
28866
  case "nextjs":
@@ -27091,8 +28943,8 @@ async function addWorkspaceCommand(options = {}) {
27091
28943
  let workspaceName = options.name;
27092
28944
  if (!workspaceName) {
27093
28945
  const nameInput = await he({
27094
- message: "Workspace name (e.g., apps/admin or packages/email):",
27095
- placeholder: "apps/dashboard",
28946
+ message: "Workspace name",
28947
+ placeholder: "apps/admin or packages/email",
27096
28948
  validate: (value) => {
27097
28949
  if (!value)
27098
28950
  return "Workspace name is required";
@@ -27120,15 +28972,15 @@ async function addWorkspaceCommand(options = {}) {
27120
28972
  let preset = options.preset;
27121
28973
  if (!preset) {
27122
28974
  const presetChoice = await ve({
27123
- message: "Choose workspace preset:",
28975
+ message: "Select workspace preset",
27124
28976
  options: [
27125
28977
  {
27126
28978
  value: "nextjs",
27127
- label: "Next.js",
27128
- hint: "Next.js 16 + React 19 + Tailwind"
28979
+ label: "Next.js Application",
28980
+ hint: "Next.js 16 + React 19 + Tailwind CSS 4 - production-ready web app"
27129
28981
  },
27130
- { value: "hono", label: "Hono API", hint: "Fast API with Bun.serve()" },
27131
- { value: "library", label: "Library", hint: "Shared package" }
28982
+ { value: "hono", label: "Hono API Server", hint: "Hono 4 + Bun.serve() - ultra-fast REST API" },
28983
+ { value: "library", label: "Shared Library", hint: "Reusable package for shared code and components" }
27132
28984
  ]
27133
28985
  });
27134
28986
  if (pD(presetChoice)) {
@@ -27166,18 +29018,18 @@ async function addWorkspaceCommand(options = {}) {
27166
29018
  spinner.stop("Dependencies installed");
27167
29019
  M2.success(`Workspace "${workspaceName}" created successfully!`);
27168
29020
  const devCommand = preset === "nextjs" ? "next dev" : preset === "hono" ? "bun dev" : "bun run build";
27169
- Me(`${import_picocolors5.default.bold("Next steps:")}
29021
+ Me(`${import_picocolors4.default.bold("Next steps:")}
27170
29022
 
27171
- ${import_picocolors5.default.cyan(`cd ${workspaceName}`)}
27172
- ${import_picocolors5.default.cyan(devCommand)}
29023
+ ${import_picocolors4.default.cyan(`cd ${workspaceName}`)}
29024
+ ${import_picocolors4.default.cyan(devCommand)}
27173
29025
 
27174
- ${import_picocolors5.default.bold("Workspace info:")}
29026
+ ${import_picocolors4.default.bold("Workspace info:")}
27175
29027
  Name: ${getWorkspaceName(workspaceName)}
27176
29028
  Type: ${preset}
27177
29029
  Path: ${workspaceName}
27178
29030
 
27179
- ${preset === "library" ? `${import_picocolors5.default.bold("Usage in other workspaces:")}
27180
- import { example } from '${getWorkspaceName(workspaceName)}'` : ""}`, import_picocolors5.default.green("Workspace ready!"));
29031
+ ${preset === "library" ? `${import_picocolors4.default.bold("Usage in other workspaces:")}
29032
+ import { example } from '${getWorkspaceName(workspaceName)}'` : ""}`, import_picocolors4.default.green("Workspace ready!"));
27181
29033
  } catch (error) {
27182
29034
  spinner.stop("Failed");
27183
29035
  throw error;
@@ -27187,7 +29039,7 @@ ${preset === "library" ? `${import_picocolors5.default.bold("Usage in other work
27187
29039
  // src/commands/add/package.ts
27188
29040
  init_dist();
27189
29041
  init_src();
27190
- var import_picocolors6 = __toESM(require_picocolors(), 1);
29042
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
27191
29043
  async function generatePackageFiles(packagePath, packageName, type) {
27192
29044
  const { writeFile: writeFile2 } = await Promise.resolve().then(() => (init_src(), exports_src));
27193
29045
  await ensureDirectory(join(packagePath, "src"));
@@ -27312,8 +29164,8 @@ async function addPackageCommand(options = {}) {
27312
29164
  let packageName = options.name;
27313
29165
  if (!packageName) {
27314
29166
  const nameInput = await he({
27315
- message: "Package name (e.g., @myapp/email or utils):",
27316
- placeholder: "@myapp/email",
29167
+ message: "Package name",
29168
+ placeholder: "@myapp/email or utils",
27317
29169
  validate: (value) => {
27318
29170
  if (!value)
27319
29171
  return "Package name is required";
@@ -27350,12 +29202,12 @@ async function addPackageCommand(options = {}) {
27350
29202
  let type = options.type;
27351
29203
  if (!type) {
27352
29204
  const typeChoice = await ve({
27353
- message: "Choose package type:",
29205
+ message: "Select package type",
27354
29206
  options: [
27355
- { value: "library", label: "Library", hint: "Shared code/components" },
27356
- { value: "utils", label: "Utils", hint: "Utility functions" },
27357
- { value: "types", label: "Types", hint: "TypeScript types" },
27358
- { value: "config", label: "Config", hint: "Configuration" }
29207
+ { value: "library", label: "Library", hint: "Shared code and components - reusable across workspaces" },
29208
+ { value: "utils", label: "Utilities", hint: "Utility functions and helpers - common operations" },
29209
+ { value: "types", label: "Type Definitions", hint: "Shared TypeScript types and interfaces" },
29210
+ { value: "config", label: "Configuration", hint: "Shared configuration files and settings" }
27359
29211
  ]
27360
29212
  });
27361
29213
  if (pD(typeChoice)) {
@@ -27400,31 +29252,148 @@ async function addPackageCommand(options = {}) {
27400
29252
  await installDependencies(cwd2, {});
27401
29253
  spinner.stop("Dependencies installed");
27402
29254
  M2.success(`Package "${fullPackageName}" created successfully!`);
27403
- Me(`${import_picocolors6.default.bold("Next steps:")}
29255
+ Me(`${import_picocolors5.default.bold("Next steps:")}
27404
29256
 
27405
- ${import_picocolors6.default.bold("1. Use in other workspaces:")}
27406
- ${import_picocolors6.default.cyan(`import { example } from '${fullPackageName}'`)}
29257
+ ${import_picocolors5.default.bold("1. Use in other workspaces:")}
29258
+ ${import_picocolors5.default.cyan(`import { example } from '${fullPackageName}'`)}
27407
29259
 
27408
- ${import_picocolors6.default.bold("2. Add to workspace dependencies:")}
27409
- ${import_picocolors6.default.dim("// In apps/web/package.json")}
27410
- ${import_picocolors6.default.cyan('"dependencies": {')}
27411
- ${import_picocolors6.default.cyan(` "${fullPackageName}": "workspace:*"`)}
27412
- ${import_picocolors6.default.cyan("}")}
29260
+ ${import_picocolors5.default.bold("2. Add to workspace dependencies:")}
29261
+ ${import_picocolors5.default.dim("// In apps/web/package.json")}
29262
+ ${import_picocolors5.default.cyan('"dependencies": {')}
29263
+ ${import_picocolors5.default.cyan(` "${fullPackageName}": "workspace:*"`)}
29264
+ ${import_picocolors5.default.cyan("}")}
27413
29265
 
27414
- ${import_picocolors6.default.bold("3. Develop the package:")}
27415
- ${import_picocolors6.default.cyan(`cd ${workspacePath}`)}
27416
- ${import_picocolors6.default.cyan("# Edit src/index.ts")}
29266
+ ${import_picocolors5.default.bold("3. Develop the package:")}
29267
+ ${import_picocolors5.default.cyan(`cd ${workspacePath}`)}
29268
+ ${import_picocolors5.default.cyan("# Edit src/index.ts")}
27417
29269
 
27418
- ${import_picocolors6.default.bold("Package info:")}
29270
+ ${import_picocolors5.default.bold("Package info:")}
27419
29271
  Name: ${fullPackageName}
27420
29272
  Type: ${type}
27421
- Path: ${workspacePath}`, import_picocolors6.default.green("Package ready!"));
29273
+ Path: ${workspacePath}`, import_picocolors5.default.green("Package ready!"));
27422
29274
  } catch (error) {
27423
29275
  spinner.stop("Failed");
27424
29276
  throw error;
27425
29277
  }
27426
29278
  }
27427
29279
 
29280
+ // src/commands/add/component.ts
29281
+ init_dist();
29282
+ import { existsSync } from "fs";
29283
+ async function addComponentCommand(options = {}) {
29284
+ const cwd2 = options.cwd || process.cwd();
29285
+ const spinner = Y2();
29286
+ const componentsJsonPath = join(cwd2, "components.json");
29287
+ const isMonorepo = existsSync(join(cwd2, "packages/ui/components.json"));
29288
+ if (!existsSync(componentsJsonPath) && !isMonorepo) {
29289
+ M2.error("shadcn/ui is not configured in this project.");
29290
+ M2.info("Run `bunkit init` with --ui-library shadcn to set up shadcn/ui first.");
29291
+ process.exit(1);
29292
+ }
29293
+ const targetPath = isMonorepo ? join(cwd2, "packages/ui") : cwd2;
29294
+ let components = [];
29295
+ if (options.all) {
29296
+ const popularComponents = [
29297
+ "button",
29298
+ "card",
29299
+ "input",
29300
+ "label",
29301
+ "textarea",
29302
+ "select",
29303
+ "checkbox",
29304
+ "radio-group",
29305
+ "switch",
29306
+ "dialog",
29307
+ "dropdown-menu",
29308
+ "alert",
29309
+ "badge",
29310
+ "avatar",
29311
+ "separator",
29312
+ "skeleton",
29313
+ "tabs",
29314
+ "accordion",
29315
+ "alert-dialog",
29316
+ "aspect-ratio",
29317
+ "breadcrumb",
29318
+ "calendar",
29319
+ "carousel",
29320
+ "chart",
29321
+ "collapsible",
29322
+ "command",
29323
+ "context-menu",
29324
+ "drawer",
29325
+ "form",
29326
+ "hover-card",
29327
+ "menubar",
29328
+ "navigation-menu",
29329
+ "popover",
29330
+ "progress",
29331
+ "scroll-area",
29332
+ "sheet",
29333
+ "slider",
29334
+ "sonner",
29335
+ "table",
29336
+ "toast",
29337
+ "toggle",
29338
+ "tooltip"
29339
+ ];
29340
+ const selected = await fe({
29341
+ message: "Select shadcn/ui components to install",
29342
+ options: popularComponents.map((comp) => ({
29343
+ value: comp,
29344
+ label: comp
29345
+ })),
29346
+ required: true
29347
+ });
29348
+ if (pD(selected)) {
29349
+ xe("Operation cancelled.");
29350
+ process.exit(0);
29351
+ }
29352
+ components = selected;
29353
+ } else if (options.components && options.components.length > 0) {
29354
+ components = options.components;
29355
+ } else {
29356
+ const componentInput = await he({
29357
+ message: "Component name(s)",
29358
+ placeholder: "button,card,input (comma-separated)",
29359
+ validate: (value) => {
29360
+ if (!value.trim()) {
29361
+ return "Please enter at least one component name";
29362
+ }
29363
+ }
29364
+ });
29365
+ if (pD(componentInput)) {
29366
+ xe("Operation cancelled.");
29367
+ process.exit(0);
29368
+ }
29369
+ components = componentInput.split(/[,\s]+/).map((c3) => c3.trim()).filter(Boolean);
29370
+ }
29371
+ if (components.length === 0) {
29372
+ M2.error("No components specified.");
29373
+ process.exit(1);
29374
+ }
29375
+ spinner.start(`Installing ${components.length} component(s)...`);
29376
+ try {
29377
+ await installShadcnComponents(targetPath, components, {
29378
+ silent: false,
29379
+ cwd: targetPath
29380
+ });
29381
+ spinner.stop(`\u2705 Installed: ${components.join(", ")}`);
29382
+ if (isMonorepo) {
29383
+ Me(`Components installed in packages/ui. Import them using:
29384
+ import { Button } from "@workspace/ui/components/ui/button"`, "Usage");
29385
+ } else {
29386
+ Me(`Import components using:
29387
+ import { Button } from "@/components/ui/button"`, "Usage");
29388
+ }
29389
+ } catch (error) {
29390
+ spinner.stop("\u274C Failed to install components");
29391
+ M2.error(error.message);
29392
+ M2.info("Try installing manually: bunx shadcn@latest add " + components.join(" "));
29393
+ process.exit(1);
29394
+ }
29395
+ }
29396
+
27428
29397
  // src/commands/add.ts
27429
29398
  async function addCommand(feature, options) {
27430
29399
  try {
@@ -27443,9 +29412,16 @@ async function addCommand(feature, options) {
27443
29412
  cwd: process.cwd()
27444
29413
  });
27445
29414
  break;
29415
+ case "component":
29416
+ await addComponentCommand({
29417
+ components: options.components,
29418
+ all: options.all,
29419
+ cwd: process.cwd()
29420
+ });
29421
+ break;
27446
29422
  default:
27447
29423
  M2.error(`Unknown feature: ${feature}`);
27448
- M2.info(`Available features: workspace, package`);
29424
+ M2.info(`Available features: workspace, package, component`);
27449
29425
  process.exit(1);
27450
29426
  }
27451
29427
  } catch (error) {
@@ -27457,37 +29433,78 @@ async function addCommand(feature, options) {
27457
29433
  var packageJson = await Bun.file(new URL("../package.json", import.meta.url)).json();
27458
29434
  var VERSION = packageJson.version;
27459
29435
  var program2 = new Command;
27460
- program2.name("bunkit").description("Bake production-ready apps in seconds").version(VERSION);
27461
- program2.command("init").description("Create a new project with full customization").option("--name <name>", "Project name").option("--preset <preset>", "Preset type (minimal, web, api, full)").option("--database <database>", "Database (postgres-drizzle, supabase, sqlite-drizzle, none)").option("--code-quality <quality>", "Code quality (ultracite, biome)").option("--ts-strictness <strictness>", "TypeScript strictness (strict, moderate, loose)").option("--ui-library <library>", "UI library (shadcn, none)").option("--css-framework <framework>", "CSS framework (tailwind, vanilla, css-modules)").option("--testing <framework>", "Testing framework (bun-test, vitest, none)").option("--docker", "Add Docker configuration").option("--cicd", "Add GitHub Actions CI/CD").option("--no-git", "Skip git initialization").option("--no-install", "Skip dependency installation").option("--non-interactive", "Run without prompts (requires all options)").action(async (options) => {
29436
+ program2.name("bunkit").description("Bake production-ready apps in seconds | Modern CLI for Bun-powered projects").version(VERSION).usage("<command> [options]").addHelpText("after", `
29437
+ Examples:
29438
+ $ bunkit init Create a new project interactively
29439
+ $ bunkit create web my-app Create a Next.js web application
29440
+ $ bunkit add workspace Add a new workspace to monorepo
29441
+ $ bunkit add component --all Browse and add shadcn/ui components
29442
+
29443
+ For more information, visit: https://github.com/Arakiss/bunkit
29444
+ `);
29445
+ program2.command("init").description("Create a new project with full customization options").alias("i").option("--name <name>", "Project name (kebab-case recommended, e.g., my-awesome-app)").option("--preset <preset>", "Project preset: minimal | web | api | full").option("--database <database>", "Database option: postgres-drizzle | supabase | supabase-drizzle | sqlite-drizzle | none").option("--supabase-preset <preset>", "Supabase configuration preset: full-stack | auth-only | database-only | custom").option("--supabase-features <features>", "Comma-separated Supabase features: auth,storage,realtime,edge-functions,database").option("--code-quality <tool>", "Code quality tool: ultracite | biome").option("--ts-strictness <level>", "TypeScript strictness level: strict | moderate | loose").option("--ui-library <library>", "UI component library: shadcn | none").option("--css-framework <framework>", "CSS framework: tailwind | vanilla | css-modules").option("--shadcn-style <style>", "shadcn/ui component style: new-york | default").option("--shadcn-base-color <color>", "shadcn/ui base color theme: neutral | gray | zinc | stone | slate").option("--shadcn-radius <radius>", "shadcn/ui border radius (CSS value, e.g., 0.5rem, 8px)").option("--testing <framework>", "Testing framework: bun-test | vitest | none").option("--docker", "Include Docker configuration files").option("--cicd", "Include GitHub Actions CI/CD workflow").option("--no-git", "Skip Git repository initialization").option("--no-install", "Skip dependency installation after project creation").option("--non-interactive", "Run in non-interactive mode (requires all options via flags)").addHelpText("after", `
29446
+ Examples:
29447
+ $ bunkit init Interactive project creation
29448
+ $ bunkit init --name my-app --preset web Quick web app creation
29449
+ $ bunkit init --preset full --database supabase Full-stack with Supabase
29450
+
29451
+ Presets:
29452
+ minimal Single-file project, clean start
29453
+ web Next.js 16 + React 19 web application
29454
+ api Hono API server with Bun.serve()
29455
+ full Full-stack monorepo (web + api + packages)
29456
+ `).action(async (options) => {
27462
29457
  showBanner(VERSION);
27463
29458
  try {
27464
29459
  await enhancedInitCommand(options);
27465
- Se(import_picocolors7.default.green("\u2728 Done! Your project is ready to bake! \uD83C\uDF5E"));
29460
+ Se(import_picocolors6.default.green("\u2728 Done! Your project is ready to bake! \uD83C\uDF5E"));
27466
29461
  } catch (error) {
27467
29462
  M2.error(error.message);
27468
- Se(import_picocolors7.default.red("\u274C Project creation failed"));
29463
+ Se(import_picocolors6.default.red("\u274C Project creation failed"));
27469
29464
  process.exit(1);
27470
29465
  }
27471
29466
  });
27472
- program2.command("create").argument("<preset>", "Preset type (minimal, web, api, full)").argument("<name>", "Project name").option("--no-git", "Skip git initialization").option("--no-install", "Skip dependency installation").description("Create a new project quickly").action(async (preset, name, options) => {
29467
+ program2.command("create").alias("c").argument("<preset>", "Project preset: minimal | web | api | full").argument("<name>", "Project name (kebab-case recommended)").option("--no-git", "Skip Git repository initialization").option("--no-install", "Skip dependency installation after project creation").description("Quick project creation with sensible defaults (non-interactive)").addHelpText("after", `
29468
+ Examples:
29469
+ $ bunkit create web my-app Create Next.js web application
29470
+ $ bunkit create api my-api Create Hono API server
29471
+ $ bunkit create full my-saas Create full-stack monorepo
29472
+ $ bunkit create minimal my-tool Create minimal Bun project
29473
+
29474
+ Note: This command uses sensible defaults. Use 'bunkit init' for full customization.
29475
+ `).action(async (preset, name, options) => {
27473
29476
  showBanner(VERSION);
27474
29477
  try {
27475
29478
  await createCommand2(preset, name, options);
27476
- Se(import_picocolors7.default.green("\u2728 Done! Your project is ready to bake! \uD83C\uDF5E"));
29479
+ Se(import_picocolors6.default.green("\u2728 Done! Your project is ready to bake! \uD83C\uDF5E"));
27477
29480
  } catch (error) {
27478
29481
  M2.error(error.message);
27479
- Se(import_picocolors7.default.red("\u274C Project creation failed"));
29482
+ Se(import_picocolors6.default.red("\u274C Project creation failed"));
27480
29483
  process.exit(1);
27481
29484
  }
27482
29485
  });
27483
- program2.command("add").argument("<feature>", "Feature to add (workspace, package)").option("--name <name>", "Name for the feature").option("--preset <preset>", "Preset for workspace (nextjs, hono, library)").option("--type <type>", "Type for package (library, utils, types, config)").description("Add workspace or package to monorepo").action(async (feature, options) => {
29486
+ program2.command("add").alias("a").argument("<feature>", "Feature type: workspace | package | component").option("--name <name>", "Feature name (e.g., apps/admin, @myapp/utils, button)").option("--preset <preset>", "Workspace preset: nextjs | hono | library").option("--type <type>", "Package type: library | utils | types | config").option("--components <components>", "Comma-separated component names (e.g., button,card,input)").option("--all", "Show interactive component browser (for component feature)").description("Add workspace, shared package, or shadcn/ui component to existing project").addHelpText("after", `
29487
+ Examples:
29488
+ $ bunkit add workspace --name apps/admin --preset nextjs
29489
+ $ bunkit add package --name @myapp/utils --type utils
29490
+ $ bunkit add component --components button,card,input
29491
+ $ bunkit add component --all
29492
+
29493
+ Features:
29494
+ workspace Add a new workspace to monorepo (app or package)
29495
+ package Add a shared package to monorepo
29496
+ component Add shadcn/ui components (requires shadcn/ui setup)
29497
+ `).action(async (feature, options) => {
27484
29498
  showBanner(VERSION);
27485
29499
  try {
27486
- await addCommand(feature, options);
27487
- Se(import_picocolors7.default.green("\u2728 Feature added successfully! \uD83C\uDF5E"));
29500
+ const parsedOptions = {
29501
+ ...options,
29502
+ components: options.components && typeof options.components === "string" ? options.components.split(",").map((c3) => c3.trim()) : options.components
29503
+ };
29504
+ await addCommand(feature, parsedOptions);
27488
29505
  } catch (error) {
27489
29506
  M2.error(error.message);
27490
- Se(import_picocolors7.default.red("\u274C Feature installation failed"));
29507
+ Se(import_picocolors6.default.red("\u274C Feature installation failed"));
27491
29508
  process.exit(1);
27492
29509
  }
27493
29510
  });