bunkit-cli 1.2.1 → 1.3.1

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 (2) hide show
  1. package/dist/index.js +1668 -148
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14851,7 +14851,396 @@ var init_monorepo = __esm(() => {
14851
14851
  init_fs();
14852
14852
  });
14853
14853
 
14854
- // ../core/src/presets.ts
14854
+ // ../core/src/presets/registry.ts
14855
+ class PresetRegistry {
14856
+ static aliasMap = null;
14857
+ static getAliasMap() {
14858
+ if (!this.aliasMap) {
14859
+ this.aliasMap = new Map;
14860
+ for (const [name, definition] of Object.entries(PRESET_DEFINITIONS)) {
14861
+ this.aliasMap.set(name, name);
14862
+ for (const alias of definition.aliases) {
14863
+ this.aliasMap.set(alias, name);
14864
+ }
14865
+ }
14866
+ }
14867
+ return this.aliasMap;
14868
+ }
14869
+ static normalize(input) {
14870
+ const map = this.getAliasMap();
14871
+ return map.get(input) || null;
14872
+ }
14873
+ static get(input) {
14874
+ const normalized = this.normalize(input);
14875
+ if (!normalized)
14876
+ return null;
14877
+ return PRESET_DEFINITIONS[normalized];
14878
+ }
14879
+ static hasCapability(input, capability) {
14880
+ const preset = this.get(input);
14881
+ if (!preset)
14882
+ return false;
14883
+ return preset.capabilities[capability];
14884
+ }
14885
+ static isMonorepo(input) {
14886
+ return this.hasCapability(input, "isMonorepo");
14887
+ }
14888
+ static getSelectOptions() {
14889
+ return Object.values(PRESET_DEFINITIONS).map((preset) => ({
14890
+ value: preset.name,
14891
+ label: `${preset.emoji} ${preset.displayName}`,
14892
+ hint: preset.hint
14893
+ }));
14894
+ }
14895
+ static getPresetsWithCapability(capability) {
14896
+ return Object.values(PRESET_DEFINITIONS).filter((preset) => preset.capabilities[capability]);
14897
+ }
14898
+ static isValid(input) {
14899
+ return this.normalize(input) !== null;
14900
+ }
14901
+ static getAllValidNames() {
14902
+ return Array.from(this.getAliasMap().keys());
14903
+ }
14904
+ }
14905
+ var PRESET_DEFINITIONS;
14906
+ var init_registry = __esm(() => {
14907
+ PRESET_DEFINITIONS = {
14908
+ minimal: {
14909
+ name: "minimal",
14910
+ displayName: "Minimal",
14911
+ description: "Single-file Bun project",
14912
+ hint: "Single-file Bun project - perfect for CLIs and scripts",
14913
+ emoji: "\u26A1",
14914
+ aliases: [],
14915
+ capabilities: {
14916
+ database: false,
14917
+ cssFramework: false,
14918
+ uiLibrary: false,
14919
+ auth: false,
14920
+ redis: false,
14921
+ docker: true,
14922
+ cicd: true,
14923
+ isMonorepo: false,
14924
+ hasApi: false,
14925
+ hasWeb: false
14926
+ },
14927
+ devCommand: "bun run dev",
14928
+ rootDependencies: {},
14929
+ rootDevDependencies: {
14930
+ "@types/bun": "latest",
14931
+ typescript: "^5.9.3"
14932
+ }
14933
+ },
14934
+ nextjs: {
14935
+ name: "nextjs",
14936
+ displayName: "Next.js Application",
14937
+ description: "Next.js 16 + React 19 + Tailwind CSS 4",
14938
+ hint: "Next.js 16 + React 19 + Tailwind CSS 4 - production-ready web app (single repo)",
14939
+ emoji: "\uD83C\uDF10",
14940
+ aliases: ["web"],
14941
+ capabilities: {
14942
+ database: true,
14943
+ cssFramework: true,
14944
+ uiLibrary: true,
14945
+ auth: true,
14946
+ redis: false,
14947
+ docker: true,
14948
+ cicd: true,
14949
+ isMonorepo: false,
14950
+ hasApi: false,
14951
+ hasWeb: true
14952
+ },
14953
+ devCommand: "bun dev",
14954
+ rootDependencies: {
14955
+ react: "^19.2.3",
14956
+ "react-dom": "^19.2.3",
14957
+ next: "^16.0.10"
14958
+ },
14959
+ rootDevDependencies: {
14960
+ "@types/bun": "latest",
14961
+ "@types/react": "^19.2.7",
14962
+ "@types/react-dom": "^19.2.3",
14963
+ "@types/node": "^25.0.3",
14964
+ typescript: "^5.9.3",
14965
+ tailwindcss: "^4.1.18",
14966
+ "@tailwindcss/postcss": "^4.1.18",
14967
+ postcss: "^8.5.6"
14968
+ }
14969
+ },
14970
+ "hono-api": {
14971
+ name: "hono-api",
14972
+ displayName: "Hono API Server",
14973
+ description: "Hono 4 + Bun.serve()",
14974
+ hint: "Hono 4 + Bun.serve() - full-featured API with middleware ecosystem (single repo)",
14975
+ emoji: "\uD83D\uDE80",
14976
+ aliases: ["api"],
14977
+ capabilities: {
14978
+ database: true,
14979
+ cssFramework: false,
14980
+ uiLibrary: false,
14981
+ auth: true,
14982
+ redis: true,
14983
+ docker: true,
14984
+ cicd: true,
14985
+ isMonorepo: false,
14986
+ hasApi: true,
14987
+ hasWeb: false
14988
+ },
14989
+ devCommand: "bun run dev",
14990
+ rootDependencies: {
14991
+ hono: "^4.11.1"
14992
+ },
14993
+ rootDevDependencies: {
14994
+ "@types/bun": "latest",
14995
+ typescript: "^5.9.3"
14996
+ }
14997
+ },
14998
+ "bun-api": {
14999
+ name: "bun-api",
15000
+ displayName: "Bun Native API",
15001
+ description: "Bun.serve() native routing",
15002
+ hint: "Bun.serve() native routing - ultra-fast API with zero dependencies (single repo)",
15003
+ emoji: "\u26A1",
15004
+ aliases: [],
15005
+ capabilities: {
15006
+ database: true,
15007
+ cssFramework: false,
15008
+ uiLibrary: false,
15009
+ auth: true,
15010
+ redis: true,
15011
+ docker: true,
15012
+ cicd: true,
15013
+ isMonorepo: false,
15014
+ hasApi: true,
15015
+ hasWeb: false
15016
+ },
15017
+ devCommand: "bun run dev",
15018
+ rootDependencies: {},
15019
+ rootDevDependencies: {
15020
+ "@types/bun": "latest",
15021
+ typescript: "^5.9.3"
15022
+ }
15023
+ },
15024
+ "bun-fullstack": {
15025
+ name: "bun-fullstack",
15026
+ displayName: "Bun Full-Stack",
15027
+ description: "Bun.serve() + HTML imports",
15028
+ hint: "Bun.serve() + HTML imports - full-stack app without Next.js (single repo)",
15029
+ emoji: "\uD83D\uDD25",
15030
+ aliases: [],
15031
+ capabilities: {
15032
+ database: true,
15033
+ cssFramework: true,
15034
+ uiLibrary: true,
15035
+ auth: true,
15036
+ redis: true,
15037
+ docker: true,
15038
+ cicd: true,
15039
+ isMonorepo: false,
15040
+ hasApi: true,
15041
+ hasWeb: true
15042
+ },
15043
+ devCommand: "bun run dev",
15044
+ rootDependencies: {},
15045
+ rootDevDependencies: {
15046
+ "@types/bun": "latest",
15047
+ typescript: "^5.9.3",
15048
+ tailwindcss: "^4.1.18",
15049
+ "@tailwindcss/postcss": "^4.1.18",
15050
+ postcss: "^8.5.6"
15051
+ }
15052
+ },
15053
+ "nextjs-monorepo": {
15054
+ name: "nextjs-monorepo",
15055
+ displayName: "Next.js Monorepo",
15056
+ description: "Next.js + Hono + shared packages",
15057
+ hint: "Next.js + Hono + shared packages - enterprise SaaS architecture",
15058
+ emoji: "\uD83D\uDCE6",
15059
+ aliases: ["full", "monorepo-nextjs"],
15060
+ capabilities: {
15061
+ database: true,
15062
+ cssFramework: true,
15063
+ uiLibrary: true,
15064
+ auth: true,
15065
+ redis: true,
15066
+ docker: true,
15067
+ cicd: true,
15068
+ isMonorepo: true,
15069
+ hasApi: true,
15070
+ hasWeb: true
15071
+ },
15072
+ workspaceStructure: {
15073
+ apps: ["web", "platform", "api"],
15074
+ packages: ["ui", "types", "utils"],
15075
+ tooling: ["typescript"]
15076
+ },
15077
+ devCommand: "bun dev",
15078
+ rootDependencies: {},
15079
+ rootDevDependencies: {
15080
+ "@types/bun": "latest",
15081
+ typescript: "catalog:"
15082
+ },
15083
+ catalogEntries: {
15084
+ react: "^19.2.3",
15085
+ "react-dom": "^19.2.3",
15086
+ next: "^16.0.10",
15087
+ "@types/react": "^19.2.7",
15088
+ "@types/react-dom": "^19.2.3",
15089
+ hono: "^4.11.1",
15090
+ "drizzle-orm": "^0.45.1",
15091
+ "drizzle-kit": "^0.31.8",
15092
+ postgres: "^3.4.7",
15093
+ "@supabase/supabase-js": "^2.88.0",
15094
+ tailwindcss: "^4.1.18",
15095
+ "@tailwindcss/postcss": "^4.1.18",
15096
+ postcss: "^8.5.6",
15097
+ autoprefixer: "^10.4.23",
15098
+ "radix-ui": "^1.4.3",
15099
+ "@radix-ui/react-slot": "^1.2.4",
15100
+ "@base-ui/react": "^1.0.0",
15101
+ shadcn: "^3.6.2",
15102
+ "class-variance-authority": "^0.7.1",
15103
+ clsx: "^2.1.1",
15104
+ "tailwind-merge": "^3.4.0",
15105
+ "tw-animate-css": "^1.4.0",
15106
+ "@phosphor-icons/react": "^2.1.10",
15107
+ "iconoir-react": "^7.11.0",
15108
+ ultracite: "^6.4.2",
15109
+ "@biomejs/biome": "^2.3.10",
15110
+ vitest: "^4.0.16",
15111
+ "@vitest/ui": "^4.0.16",
15112
+ "@types/node": "^25.0.3",
15113
+ typescript: "^5.9.3"
15114
+ }
15115
+ },
15116
+ "bun-monorepo": {
15117
+ name: "bun-monorepo",
15118
+ displayName: "Bun Monorepo",
15119
+ description: "Full-stack monorepo with Bun.serve()",
15120
+ hint: "Full-stack monorepo with Bun.serve() - no Next.js",
15121
+ emoji: "\uD83D\uDD25",
15122
+ aliases: ["monorepo-bun"],
15123
+ capabilities: {
15124
+ database: true,
15125
+ cssFramework: true,
15126
+ uiLibrary: true,
15127
+ auth: true,
15128
+ redis: true,
15129
+ docker: true,
15130
+ cicd: true,
15131
+ isMonorepo: true,
15132
+ hasApi: true,
15133
+ hasWeb: true
15134
+ },
15135
+ workspaceStructure: {
15136
+ apps: ["web", "api"],
15137
+ packages: ["ui", "types", "utils"],
15138
+ tooling: ["typescript"]
15139
+ },
15140
+ devCommand: "bun dev",
15141
+ rootDependencies: {},
15142
+ rootDevDependencies: {
15143
+ "@types/bun": "latest",
15144
+ typescript: "catalog:"
15145
+ },
15146
+ catalogEntries: {
15147
+ react: "^19.2.3",
15148
+ "react-dom": "^19.2.3",
15149
+ "@types/react": "^19.2.7",
15150
+ "@types/react-dom": "^19.2.3",
15151
+ "drizzle-orm": "^0.45.1",
15152
+ "drizzle-kit": "^0.31.8",
15153
+ postgres: "^3.4.7",
15154
+ "@supabase/supabase-js": "^2.88.0",
15155
+ tailwindcss: "^4.1.18",
15156
+ "@tailwindcss/postcss": "^4.1.18",
15157
+ postcss: "^8.5.6",
15158
+ autoprefixer: "^10.4.23",
15159
+ "radix-ui": "^1.4.3",
15160
+ "@radix-ui/react-slot": "^1.2.4",
15161
+ "@base-ui/react": "^1.0.0",
15162
+ shadcn: "^3.6.2",
15163
+ "class-variance-authority": "^0.7.1",
15164
+ clsx: "^2.1.1",
15165
+ "tailwind-merge": "^3.4.0",
15166
+ "tw-animate-css": "^1.4.0",
15167
+ "@phosphor-icons/react": "^2.1.10",
15168
+ "iconoir-react": "^7.11.0",
15169
+ ultracite: "^6.4.2",
15170
+ "@biomejs/biome": "^2.3.10",
15171
+ vitest: "^4.0.16",
15172
+ "@vitest/ui": "^4.0.16",
15173
+ "@types/node": "^25.0.3",
15174
+ typescript: "^5.9.3"
15175
+ }
15176
+ },
15177
+ "enterprise-monorepo": {
15178
+ name: "enterprise-monorepo",
15179
+ displayName: "Enterprise Monorepo",
15180
+ description: "Multiple Next.js apps + services",
15181
+ hint: "Multiple Next.js apps + services - platform, app, service-identity",
15182
+ emoji: "\uD83C\uDFE2",
15183
+ aliases: [],
15184
+ capabilities: {
15185
+ database: true,
15186
+ cssFramework: true,
15187
+ uiLibrary: true,
15188
+ auth: true,
15189
+ redis: true,
15190
+ docker: true,
15191
+ cicd: true,
15192
+ isMonorepo: true,
15193
+ hasApi: true,
15194
+ hasWeb: true
15195
+ },
15196
+ workspaceStructure: {
15197
+ apps: ["web", "platform", "admin", "api", "service-identity"],
15198
+ packages: ["ui", "types", "utils", "db", "auth"],
15199
+ tooling: ["typescript", "testing"]
15200
+ },
15201
+ devCommand: "bun dev",
15202
+ rootDependencies: {},
15203
+ rootDevDependencies: {
15204
+ "@types/bun": "latest",
15205
+ typescript: "catalog:"
15206
+ },
15207
+ catalogEntries: {
15208
+ react: "^19.2.3",
15209
+ "react-dom": "^19.2.3",
15210
+ next: "^16.0.10",
15211
+ "@types/react": "^19.2.7",
15212
+ "@types/react-dom": "^19.2.3",
15213
+ hono: "^4.11.1",
15214
+ "drizzle-orm": "^0.45.1",
15215
+ "drizzle-kit": "^0.31.8",
15216
+ postgres: "^3.4.7",
15217
+ "@supabase/supabase-js": "^2.88.0",
15218
+ tailwindcss: "^4.1.18",
15219
+ "@tailwindcss/postcss": "^4.1.18",
15220
+ postcss: "^8.5.6",
15221
+ autoprefixer: "^10.4.23",
15222
+ "radix-ui": "^1.4.3",
15223
+ "@radix-ui/react-slot": "^1.2.4",
15224
+ "@base-ui/react": "^1.0.0",
15225
+ shadcn: "^3.6.2",
15226
+ "class-variance-authority": "^0.7.1",
15227
+ clsx: "^2.1.1",
15228
+ "tailwind-merge": "^3.4.0",
15229
+ "tw-animate-css": "^1.4.0",
15230
+ "@phosphor-icons/react": "^2.1.10",
15231
+ "iconoir-react": "^7.11.0",
15232
+ ultracite: "^6.4.2",
15233
+ "@biomejs/biome": "^2.3.10",
15234
+ vitest: "^4.0.16",
15235
+ "@vitest/ui": "^4.0.16",
15236
+ "@types/node": "^25.0.3",
15237
+ typescript: "^5.9.3"
15238
+ }
15239
+ }
15240
+ };
15241
+ });
15242
+
15243
+ // ../core/src/presets/custom.ts
14855
15244
  function getPresetsDir() {
14856
15245
  return join(process.env.HOME || process.env.USERPROFILE || ".", ".bunkit");
14857
15246
  }
@@ -14896,11 +15285,17 @@ async function listCustomPresets() {
14896
15285
  const presets = await loadCustomPresets();
14897
15286
  return Object.values(presets);
14898
15287
  }
14899
- var init_presets = __esm(() => {
15288
+ var init_custom2 = __esm(() => {
14900
15289
  init_dist();
14901
15290
  init_fs();
14902
15291
  });
14903
15292
 
15293
+ // ../core/src/presets/index.ts
15294
+ var init_presets = __esm(() => {
15295
+ init_registry();
15296
+ init_custom2();
15297
+ });
15298
+
14904
15299
  // ../core/src/project.ts
14905
15300
  async function createProject(config) {
14906
15301
  const projectPath = join(process.cwd(), config.path);
@@ -15064,7 +15459,11 @@ function createTemplateContext(config) {
15064
15459
  envExample: config.envExample,
15065
15460
  pathAliases: config.pathAliases,
15066
15461
  shadcnStyle: config.shadcnStyle,
15462
+ shadcnBase: config.shadcnBase,
15067
15463
  shadcnBaseColor: config.shadcnBaseColor,
15464
+ shadcnIconLibrary: config.shadcnIconLibrary,
15465
+ shadcnMenuAccent: config.shadcnMenuAccent,
15466
+ shadcnMenuColor: config.shadcnMenuColor,
15068
15467
  shadcnRadius: config.shadcnRadius,
15069
15468
  supabasePreset: config.supabasePreset,
15070
15469
  supabaseFeatures: config.supabaseFeatures,
@@ -19091,8 +19490,12 @@ var init_types2 = __esm(() => {
19091
19490
  tsStrictness: exports_external.enum(["strict", "moderate", "loose"]).default("strict"),
19092
19491
  uiLibrary: exports_external.enum(["shadcn", "none"]).optional(),
19093
19492
  cssFramework: exports_external.enum(["tailwind", "vanilla", "css-modules"]).optional(),
19094
- shadcnStyle: exports_external.enum(["new-york", "default"]).optional(),
19493
+ shadcnStyle: exports_external.enum(["radix-maia", "radix-vega", "radix-nova", "radix-lyra", "radix-mira", "new-york", "default"]).optional(),
19494
+ shadcnBase: exports_external.enum(["radix", "base-ui"]).optional(),
19095
19495
  shadcnBaseColor: exports_external.enum(["neutral", "gray", "zinc", "stone", "slate"]).optional(),
19496
+ shadcnIconLibrary: exports_external.enum(["phosphor", "lucide", "iconoir"]).optional(),
19497
+ shadcnMenuAccent: exports_external.enum(["subtle", "bold"]).optional(),
19498
+ shadcnMenuColor: exports_external.enum(["default", "muted"]).optional(),
19096
19499
  shadcnRadius: exports_external.string().optional(),
19097
19500
  testing: exports_external.enum(["bun-test", "vitest", "none"]).default("bun-test"),
19098
19501
  docker: exports_external.boolean().default(false),
@@ -19195,6 +19598,8 @@ __export(exports_src, {
19195
19598
  addWorkspaceToRoot: () => addWorkspaceToRoot,
19196
19599
  addToCatalog: () => addToCatalog,
19197
19600
  ProjectConfigSchema: () => ProjectConfigSchema,
19601
+ PresetRegistry: () => PresetRegistry,
19602
+ PRESET_DEFINITIONS: () => PRESET_DEFINITIONS,
19198
19603
  FeatureConfigSchema: () => FeatureConfigSchema
19199
19604
  });
19200
19605
  var init_src = __esm(() => {
@@ -21360,6 +21765,240 @@ var require_commander = __commonJS((exports) => {
21360
21765
  exports.InvalidOptionArgumentError = InvalidArgumentError;
21361
21766
  });
21362
21767
 
21768
+ // ../templates/src/shared/package-json.ts
21769
+ var exports_package_json = {};
21770
+ __export(exports_package_json, {
21771
+ writeUtilsPackageJson: () => writeUtilsPackageJson,
21772
+ writeUiPackageJson: () => writeUiPackageJson,
21773
+ writeTypesPackageJson: () => writeTypesPackageJson,
21774
+ writePackageJson: () => writePackageJson,
21775
+ writeNextjsAppPackageJson: () => writeNextjsAppPackageJson,
21776
+ writeMonorepoRootPackageJson: () => writeMonorepoRootPackageJson,
21777
+ writeHonoApiPackageJson: () => writeHonoApiPackageJson
21778
+ });
21779
+ async function writePackageJson(directory, options) {
21780
+ const packageJson = {
21781
+ name: options.name,
21782
+ version: options.version ?? "0.0.0"
21783
+ };
21784
+ if (options.private !== undefined) {
21785
+ packageJson.private = options.private;
21786
+ }
21787
+ if (options.description) {
21788
+ packageJson.description = options.description;
21789
+ }
21790
+ if (options.main) {
21791
+ packageJson.main = options.main;
21792
+ }
21793
+ if (options.types) {
21794
+ packageJson.types = options.types;
21795
+ }
21796
+ if (options.exports) {
21797
+ packageJson.exports = options.exports;
21798
+ }
21799
+ if (options.workspaces) {
21800
+ packageJson.workspaces = options.workspaces;
21801
+ }
21802
+ if (options.scripts && Object.keys(options.scripts).length > 0) {
21803
+ packageJson.scripts = options.scripts;
21804
+ }
21805
+ if (options.dependencies && Object.keys(options.dependencies).length > 0) {
21806
+ packageJson.dependencies = options.dependencies;
21807
+ }
21808
+ if (options.devDependencies && Object.keys(options.devDependencies).length > 0) {
21809
+ packageJson.devDependencies = options.devDependencies;
21810
+ }
21811
+ if (options.peerDependencies && Object.keys(options.peerDependencies).length > 0) {
21812
+ packageJson.peerDependencies = options.peerDependencies;
21813
+ }
21814
+ if (options.catalog && Object.keys(options.catalog).length > 0) {
21815
+ packageJson.catalog = options.catalog;
21816
+ }
21817
+ await writeFile(join(directory, "package.json"), JSON.stringify(packageJson, null, 2));
21818
+ }
21819
+ async function writeMonorepoRootPackageJson(projectPath, projectName, catalog, options = {}) {
21820
+ const scripts = {
21821
+ dev: 'bun run --filter "*" dev',
21822
+ build: 'bun run --filter "*" build',
21823
+ lint: options.codeQuality === "ultracite" ? "ultracite check ." : "biome check .",
21824
+ format: options.codeQuality === "ultracite" ? "ultracite fix ." : "biome format --write .",
21825
+ test: "bun test"
21826
+ };
21827
+ if (options.hasWeb) {
21828
+ scripts["dev:web"] = 'bun run --filter "@*/web" dev';
21829
+ }
21830
+ if (options.hasPlatform) {
21831
+ scripts["dev:platform"] = 'bun run --filter "@*/platform" dev';
21832
+ }
21833
+ if (options.hasApi) {
21834
+ scripts["dev:api"] = 'bun run --filter "@*/api" dev';
21835
+ scripts.debug = "bun --inspect apps/api/src/index.ts";
21836
+ scripts["debug:brk"] = "bun --inspect-brk apps/api/src/index.ts";
21837
+ scripts["debug:wait"] = "bun --inspect-wait apps/api/src/index.ts";
21838
+ }
21839
+ await writePackageJson(projectPath, {
21840
+ name: `${projectName}-monorepo`,
21841
+ version: "0.0.0",
21842
+ private: true,
21843
+ workspaces: ["apps/*", "packages/*"],
21844
+ scripts,
21845
+ devDependencies: {
21846
+ "@types/bun": "latest",
21847
+ typescript: "catalog:"
21848
+ },
21849
+ catalog
21850
+ });
21851
+ }
21852
+ async function writeNextjsAppPackageJson(appPath, scopeName, appName, options = {}) {
21853
+ const dependencies = {
21854
+ react: "catalog:",
21855
+ "react-dom": "catalog:",
21856
+ next: "catalog:",
21857
+ "iconoir-react": "catalog:"
21858
+ };
21859
+ if (options.usesTypes) {
21860
+ dependencies[`@${scopeName}/types`] = "workspace:*";
21861
+ }
21862
+ if (options.usesUi) {
21863
+ dependencies[`@${scopeName}/ui`] = "workspace:*";
21864
+ }
21865
+ const devDependencies = {
21866
+ "@types/react": "catalog:",
21867
+ "@types/react-dom": "catalog:",
21868
+ "@types/node": "catalog:",
21869
+ typescript: "catalog:",
21870
+ tailwindcss: "catalog:",
21871
+ "@tailwindcss/postcss": "catalog:",
21872
+ postcss: "catalog:"
21873
+ };
21874
+ await writePackageJson(appPath, {
21875
+ name: `@${scopeName}/${appName}`,
21876
+ version: "0.0.0",
21877
+ private: true,
21878
+ scripts: {
21879
+ dev: "next dev",
21880
+ build: "next build",
21881
+ start: "next start",
21882
+ debug: "bun --inspect node_modules/.bin/next dev",
21883
+ "debug:brk": "bun --inspect-brk node_modules/.bin/next dev",
21884
+ "debug:wait": "bun --inspect-wait node_modules/.bin/next dev"
21885
+ },
21886
+ dependencies,
21887
+ devDependencies
21888
+ });
21889
+ }
21890
+ async function writeHonoApiPackageJson(appPath, scopeName, options = {}) {
21891
+ const dependencies = {
21892
+ hono: "catalog:"
21893
+ };
21894
+ if (options.usesTypes) {
21895
+ dependencies[`@${scopeName}/types`] = "workspace:*";
21896
+ }
21897
+ if (options.usesDb) {
21898
+ dependencies[`@${scopeName}/db`] = "workspace:*";
21899
+ }
21900
+ await writePackageJson(appPath, {
21901
+ name: `@${scopeName}/api`,
21902
+ version: "0.0.0",
21903
+ private: true,
21904
+ scripts: {
21905
+ dev: "bun --hot src/index.ts",
21906
+ build: "bun build src/index.ts --outdir dist --target bun",
21907
+ start: "bun dist/index.js",
21908
+ debug: "bun --inspect src/index.ts",
21909
+ "debug:brk": "bun --inspect-brk src/index.ts",
21910
+ "debug:wait": "bun --inspect-wait src/index.ts"
21911
+ },
21912
+ dependencies,
21913
+ devDependencies: {
21914
+ "@types/bun": "latest",
21915
+ typescript: "catalog:"
21916
+ }
21917
+ });
21918
+ }
21919
+ async function writeUiPackageJson(packagePath, scopeName) {
21920
+ await writePackageJson(packagePath, {
21921
+ name: `@${scopeName}/ui`,
21922
+ version: "0.0.0",
21923
+ private: true,
21924
+ main: "./src/index.ts",
21925
+ types: "./src/index.ts",
21926
+ exports: {
21927
+ ".": "./src/index.ts",
21928
+ "./components": "./src/components/index.ts",
21929
+ "./lib/utils": "./src/lib/utils.ts",
21930
+ "./hooks": "./src/hooks/index.ts",
21931
+ "./globals.css": "./src/styles/globals.css",
21932
+ "./postcss.config": "./postcss.config.mjs"
21933
+ },
21934
+ scripts: {
21935
+ build: "tsc --noEmit",
21936
+ lint: "tsc --noEmit"
21937
+ },
21938
+ dependencies: {
21939
+ "@radix-ui/react-slot": "catalog:",
21940
+ "class-variance-authority": "catalog:",
21941
+ clsx: "catalog:",
21942
+ "tailwind-merge": "catalog:",
21943
+ "iconoir-react": "catalog:",
21944
+ tailwindcss: "catalog:",
21945
+ "@tailwindcss/postcss": "catalog:",
21946
+ postcss: "catalog:"
21947
+ },
21948
+ devDependencies: {
21949
+ "@types/react": "catalog:",
21950
+ "@types/react-dom": "catalog:",
21951
+ typescript: "catalog:"
21952
+ },
21953
+ peerDependencies: {
21954
+ react: "^19.0.0",
21955
+ "react-dom": "^19.0.0"
21956
+ }
21957
+ });
21958
+ }
21959
+ async function writeTypesPackageJson(packagePath, scopeName) {
21960
+ await writePackageJson(packagePath, {
21961
+ name: `@${scopeName}/types`,
21962
+ version: "0.0.0",
21963
+ private: true,
21964
+ main: "./src/index.ts",
21965
+ types: "./src/index.ts",
21966
+ exports: {
21967
+ ".": "./src/index.ts"
21968
+ },
21969
+ scripts: {
21970
+ build: "tsc --noEmit",
21971
+ lint: "tsc --noEmit"
21972
+ },
21973
+ devDependencies: {
21974
+ typescript: "catalog:"
21975
+ }
21976
+ });
21977
+ }
21978
+ async function writeUtilsPackageJson(packagePath, scopeName) {
21979
+ await writePackageJson(packagePath, {
21980
+ name: `@${scopeName}/utils`,
21981
+ version: "0.0.0",
21982
+ private: true,
21983
+ main: "./src/index.ts",
21984
+ types: "./src/index.ts",
21985
+ exports: {
21986
+ ".": "./src/index.ts"
21987
+ },
21988
+ scripts: {
21989
+ build: "tsc --noEmit",
21990
+ lint: "tsc --noEmit"
21991
+ },
21992
+ devDependencies: {
21993
+ typescript: "catalog:"
21994
+ }
21995
+ });
21996
+ }
21997
+ var init_package_json = __esm(() => {
21998
+ init_src();
21999
+ init_dist();
22000
+ });
22001
+
21363
22002
  // ../../node_modules/.bun/ejs@3.1.10/node_modules/ejs/lib/utils.js
21364
22003
  var require_utils5 = __commonJS((exports) => {
21365
22004
  var regExpChars = /[|\\{}()[\]^$+*?.]/g;
@@ -27823,12 +28462,7 @@ var themes = {
27823
28462
  };
27824
28463
  function generateThemeCSS(theme, customRadius) {
27825
28464
  const radius = customRadius || theme.light.radius;
27826
- return `@import "tailwindcss";
27827
- @source "../../../apps/**/*.{ts,tsx}";
27828
- @source "../../../components/**/*.{ts,tsx}";
27829
- @source "../**/*.{ts,tsx}";
27830
-
27831
- :root {
28465
+ return `:root {
27832
28466
  --radius: ${radius};
27833
28467
  --background: ${theme.light.background};
27834
28468
  --foreground: ${theme.light.foreground};
@@ -27947,58 +28581,183 @@ function generateThemeCSS(theme, customRadius) {
27947
28581
  }
27948
28582
  `;
27949
28583
  }
27950
-
27951
- // ../templates/src/generators/shadcn.ts
27952
- async function setupShadcnWeb(projectPath, context) {
27953
- await ensureDirectory(join(projectPath, "src/components/ui"));
27954
- await ensureDirectory(join(projectPath, "src/lib"));
27955
- const style = context.shadcnStyle || "new-york";
27956
- const baseColor = context.shadcnBaseColor || "zinc";
27957
- const radius = context.shadcnRadius || "0.625rem";
27958
- const componentsJson = {
27959
- $schema: "https://ui.shadcn.com/schema.json",
27960
- style,
27961
- rsc: true,
27962
- tsx: true,
27963
- tailwind: {
27964
- config: "",
27965
- css: "src/app/globals.css",
27966
- baseColor,
27967
- cssVariables: true
27968
- },
27969
- iconLibrary: "lucide",
27970
- aliases: {
27971
- components: "@/components",
27972
- utils: "@/lib/utils",
27973
- ui: "@/components/ui",
27974
- lib: "@/lib",
27975
- hooks: "@/hooks"
27976
- }
27977
- };
27978
- await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
27979
- const utilsContent = `import { clsx, type ClassValue } from 'clsx';
27980
- import { twMerge } from 'tailwind-merge';
27981
-
27982
- export function cn(...inputs: ClassValue[]) {
27983
- return twMerge(clsx(inputs));
28584
+ function generateModernThemeCSS(baseColor, customRadius) {
28585
+ const theme = themes[baseColor] || themes.zinc;
28586
+ const radius = customRadius || "0.625rem";
28587
+ return `@theme inline {
28588
+ --color-background: var(--background);
28589
+ --color-foreground: var(--foreground);
28590
+ --font-sans: var(--font-sans);
28591
+ --font-mono: var(--font-geist-mono);
28592
+ --color-sidebar-ring: var(--sidebar-ring);
28593
+ --color-sidebar-border: var(--sidebar-border);
28594
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
28595
+ --color-sidebar-accent: var(--sidebar-accent);
28596
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
28597
+ --color-sidebar-primary: var(--sidebar-primary);
28598
+ --color-sidebar-foreground: var(--sidebar-foreground);
28599
+ --color-sidebar: var(--sidebar);
28600
+ --color-chart-5: var(--chart-5);
28601
+ --color-chart-4: var(--chart-4);
28602
+ --color-chart-3: var(--chart-3);
28603
+ --color-chart-2: var(--chart-2);
28604
+ --color-chart-1: var(--chart-1);
28605
+ --color-ring: var(--ring);
28606
+ --color-input: var(--input);
28607
+ --color-border: var(--border);
28608
+ --color-destructive: var(--destructive);
28609
+ --color-accent-foreground: var(--accent-foreground);
28610
+ --color-accent: var(--accent);
28611
+ --color-muted-foreground: var(--muted-foreground);
28612
+ --color-muted: var(--muted);
28613
+ --color-secondary-foreground: var(--secondary-foreground);
28614
+ --color-secondary: var(--secondary);
28615
+ --color-primary-foreground: var(--primary-foreground);
28616
+ --color-primary: var(--primary);
28617
+ --color-popover-foreground: var(--popover-foreground);
28618
+ --color-popover: var(--popover);
28619
+ --color-card-foreground: var(--card-foreground);
28620
+ --color-card: var(--card);
28621
+ --radius-sm: calc(var(--radius) - 4px);
28622
+ --radius-md: calc(var(--radius) - 2px);
28623
+ --radius-lg: var(--radius);
28624
+ --radius-xl: calc(var(--radius) + 4px);
28625
+ --radius-2xl: calc(var(--radius) + 8px);
28626
+ --radius-3xl: calc(var(--radius) + 12px);
28627
+ --radius-4xl: calc(var(--radius) + 16px);
27984
28628
  }
27985
- `;
27986
- await writeFile(join(projectPath, "src/lib/utils.ts"), utilsContent);
27987
- const packageJsonPath = join(projectPath, "package.json");
27988
- let packageJson = {};
27989
- try {
27990
- packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
27991
- } catch {}
27992
- if (!packageJson.dependencies) {
27993
- packageJson.dependencies = {};
27994
- }
27995
- packageJson.dependencies["@radix-ui/react-slot"] = "catalog:";
27996
- packageJson.dependencies["class-variance-authority"] = "catalog:";
27997
- packageJson.dependencies.clsx = "catalog:";
27998
- packageJson.dependencies["tailwind-merge"] = "catalog:";
27999
- packageJson.dependencies["lucide-react"] = "catalog:";
28000
- if (!packageJson.catalog) {
28001
- packageJson.catalog = {};
28629
+
28630
+ :root {
28631
+ --background: ${theme.light.background};
28632
+ --foreground: ${theme.light.foreground};
28633
+ --card: ${theme.light.card};
28634
+ --card-foreground: ${theme.light.cardForeground};
28635
+ --popover: ${theme.light.popover};
28636
+ --popover-foreground: ${theme.light.popoverForeground};
28637
+ --primary: ${theme.light.primary};
28638
+ --primary-foreground: ${theme.light.primaryForeground};
28639
+ --secondary: ${theme.light.secondary};
28640
+ --secondary-foreground: ${theme.light.secondaryForeground};
28641
+ --muted: ${theme.light.muted};
28642
+ --muted-foreground: ${theme.light.mutedForeground};
28643
+ --accent: ${theme.light.accent};
28644
+ --accent-foreground: ${theme.light.accentForeground};
28645
+ --destructive: ${theme.light.destructive};
28646
+ --border: ${theme.light.border};
28647
+ --input: ${theme.light.input};
28648
+ --ring: ${theme.light.ring};
28649
+ --chart-1: ${theme.light.chart1};
28650
+ --chart-2: ${theme.light.chart2};
28651
+ --chart-3: ${theme.light.chart3};
28652
+ --chart-4: ${theme.light.chart4};
28653
+ --chart-5: ${theme.light.chart5};
28654
+ --radius: ${radius};
28655
+ --sidebar: ${theme.light.sidebar};
28656
+ --sidebar-foreground: ${theme.light.sidebarForeground};
28657
+ --sidebar-primary: ${theme.light.sidebarPrimary};
28658
+ --sidebar-primary-foreground: ${theme.light.sidebarPrimaryForeground};
28659
+ --sidebar-accent: ${theme.light.sidebarAccent};
28660
+ --sidebar-accent-foreground: ${theme.light.sidebarAccentForeground};
28661
+ --sidebar-border: ${theme.light.sidebarBorder};
28662
+ --sidebar-ring: ${theme.light.sidebarRing};
28663
+ }
28664
+
28665
+ .dark {
28666
+ --background: ${theme.dark.background};
28667
+ --foreground: ${theme.dark.foreground};
28668
+ --card: ${theme.dark.card};
28669
+ --card-foreground: ${theme.dark.cardForeground};
28670
+ --popover: ${theme.dark.popover};
28671
+ --popover-foreground: ${theme.dark.popoverForeground};
28672
+ --primary: ${theme.dark.primary};
28673
+ --primary-foreground: ${theme.dark.primaryForeground};
28674
+ --secondary: ${theme.dark.secondary};
28675
+ --secondary-foreground: ${theme.dark.secondaryForeground};
28676
+ --muted: ${theme.dark.muted};
28677
+ --muted-foreground: ${theme.dark.mutedForeground};
28678
+ --accent: ${theme.dark.accent};
28679
+ --accent-foreground: ${theme.dark.accentForeground};
28680
+ --destructive: ${theme.dark.destructive};
28681
+ --border: ${theme.dark.border};
28682
+ --input: ${theme.dark.input};
28683
+ --ring: ${theme.dark.ring};
28684
+ --chart-1: ${theme.dark.chart1};
28685
+ --chart-2: ${theme.dark.chart2};
28686
+ --chart-3: ${theme.dark.chart3};
28687
+ --chart-4: ${theme.dark.chart4};
28688
+ --chart-5: ${theme.dark.chart5};
28689
+ --sidebar: ${theme.dark.sidebar};
28690
+ --sidebar-foreground: ${theme.dark.sidebarForeground};
28691
+ --sidebar-primary: ${theme.dark.sidebarPrimary};
28692
+ --sidebar-primary-foreground: ${theme.dark.sidebarPrimaryForeground};
28693
+ --sidebar-accent: ${theme.dark.sidebarAccent};
28694
+ --sidebar-accent-foreground: ${theme.dark.sidebarAccentForeground};
28695
+ --sidebar-border: ${theme.dark.sidebarBorder};
28696
+ --sidebar-ring: ${theme.dark.sidebarRing};
28697
+ }
28698
+
28699
+ @layer base {
28700
+ * {
28701
+ @apply border-border outline-ring/50;
28702
+ }
28703
+ body {
28704
+ @apply bg-background text-foreground;
28705
+ }
28706
+ }
28707
+ `;
28708
+ }
28709
+
28710
+ // ../templates/src/generators/shadcn.ts
28711
+ async function setupShadcnWeb(projectPath, context) {
28712
+ await ensureDirectory(join(projectPath, "src/components/ui"));
28713
+ await ensureDirectory(join(projectPath, "src/lib"));
28714
+ const style = context.shadcnStyle || "new-york";
28715
+ const baseColor = context.shadcnBaseColor || "zinc";
28716
+ const radius = context.shadcnRadius || "0.625rem";
28717
+ const componentsJson = {
28718
+ $schema: "https://ui.shadcn.com/schema.json",
28719
+ style,
28720
+ rsc: true,
28721
+ tsx: true,
28722
+ tailwind: {
28723
+ config: "",
28724
+ css: "src/app/globals.css",
28725
+ baseColor,
28726
+ cssVariables: true
28727
+ },
28728
+ iconLibrary: "lucide",
28729
+ aliases: {
28730
+ components: "@/components",
28731
+ utils: "@/lib/utils",
28732
+ ui: "@/components/ui",
28733
+ lib: "@/lib",
28734
+ hooks: "@/hooks"
28735
+ }
28736
+ };
28737
+ await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
28738
+ const utilsContent = `import { clsx, type ClassValue } from 'clsx';
28739
+ import { twMerge } from 'tailwind-merge';
28740
+
28741
+ export function cn(...inputs: ClassValue[]) {
28742
+ return twMerge(clsx(inputs));
28743
+ }
28744
+ `;
28745
+ await writeFile(join(projectPath, "src/lib/utils.ts"), utilsContent);
28746
+ const packageJsonPath = join(projectPath, "package.json");
28747
+ let packageJson = {};
28748
+ try {
28749
+ packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
28750
+ } catch {}
28751
+ if (!packageJson.dependencies) {
28752
+ packageJson.dependencies = {};
28753
+ }
28754
+ packageJson.dependencies["@radix-ui/react-slot"] = "catalog:";
28755
+ packageJson.dependencies["class-variance-authority"] = "catalog:";
28756
+ packageJson.dependencies.clsx = "catalog:";
28757
+ packageJson.dependencies["tailwind-merge"] = "catalog:";
28758
+ packageJson.dependencies["lucide-react"] = "catalog:";
28759
+ if (!packageJson.catalog) {
28760
+ packageJson.catalog = {};
28002
28761
  }
28003
28762
  packageJson.catalog["@radix-ui/react-slot"] = "^1.2.4";
28004
28763
  packageJson.catalog["class-variance-authority"] = "^0.7.1";
@@ -30266,91 +31025,707 @@ export default config;
30266
31025
  await writeFile(packageJsonPath, JSON.stringify(existingPackageJson, null, 2));
30267
31026
  await generateNextjsReadme(projectPath, context);
30268
31027
  }
30269
- // ../templates/src/render.ts
30270
- var import_ejs = __toESM(require_ejs(), 1);
30271
- // src/commands/add/component.ts
31028
+ // ../templates/src/builders/full-v2.ts
31029
+ init_src();
30272
31030
  init_dist();
30273
- async function getPackageName(cwd2) {
30274
- try {
30275
- const packageJsonPath = join(cwd2, "package.json");
30276
- if (existsSync(packageJsonPath)) {
30277
- const packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
30278
- const name = packageJson.name;
30279
- if (name?.endsWith("-monorepo")) {
30280
- return name.replace("-monorepo", "");
31031
+ init_package_json();
31032
+
31033
+ // ../templates/src/shared/ui-package.ts
31034
+ init_src();
31035
+ init_dist();
31036
+ init_package_json();
31037
+ function isModernStyle(style) {
31038
+ return style === "radix-maia" || style === "radix-vega" || style === "radix-nova" || style === "radix-lyra" || style === "radix-mira";
31039
+ }
31040
+ async function buildUiPackage(packagesPath, options) {
31041
+ const uiPath = join(packagesPath, "ui");
31042
+ await ensureDirectory(join(uiPath, "src/components"));
31043
+ await ensureDirectory(join(uiPath, "src/hooks"));
31044
+ await ensureDirectory(join(uiPath, "src/lib"));
31045
+ await ensureDirectory(join(uiPath, "src/styles"));
31046
+ await writeUiPackageJson(uiPath, options.scopeName);
31047
+ await writeFile(join(uiPath, "tsconfig.json"), JSON.stringify({
31048
+ extends: "../../tooling/typescript/library.json",
31049
+ compilerOptions: {
31050
+ jsx: "react-jsx",
31051
+ rootDir: "./src",
31052
+ outDir: "./dist",
31053
+ baseUrl: ".",
31054
+ paths: {
31055
+ "@/*": ["./src/*"]
30281
31056
  }
30282
- return name || null;
31057
+ },
31058
+ include: ["src/**/*"],
31059
+ exclude: ["node_modules"]
31060
+ }, null, 2));
31061
+ const style = options.shadcnStyle || "radix-maia";
31062
+ const useModernStyle = isModernStyle(style);
31063
+ const iconLibrary = options.shadcnIconLibrary || (useModernStyle ? "phosphor" : "iconoir");
31064
+ const componentsJson = {
31065
+ $schema: "https://ui.shadcn.com/schema.json",
31066
+ style,
31067
+ rsc: true,
31068
+ tsx: true,
31069
+ tailwind: {
31070
+ config: "",
31071
+ css: "./src/styles/globals.css",
31072
+ baseColor: options.shadcnBaseColor || "zinc",
31073
+ cssVariables: true,
31074
+ prefix: ""
31075
+ },
31076
+ iconLibrary,
31077
+ aliases: {
31078
+ components: "./src/components",
31079
+ utils: "./src/lib/utils",
31080
+ ui: "./src/components/ui",
31081
+ lib: "./src/lib",
31082
+ hooks: "./src/hooks"
30283
31083
  }
30284
- } catch {}
30285
- return null;
30286
- }
30287
- async function addComponentCommand(options = {}) {
30288
- const cwd2 = options.cwd || process.cwd();
30289
- const spinner = Y2();
30290
- const componentsJsonPath = join(cwd2, "components.json");
30291
- const isMonorepo = existsSync(join(cwd2, "packages/ui/components.json"));
30292
- if (!existsSync(componentsJsonPath) && !isMonorepo) {
30293
- M2.error("shadcn/ui is not configured in this project.");
30294
- M2.info("Run `bunkit init` with --ui-library shadcn to set up shadcn/ui first.");
30295
- process.exit(1);
31084
+ };
31085
+ if (useModernStyle) {
31086
+ componentsJson.menuColor = options.shadcnMenuColor || "default";
31087
+ componentsJson.menuAccent = options.shadcnMenuAccent || "subtle";
31088
+ componentsJson.registries = {};
30296
31089
  }
30297
- const targetPath = isMonorepo ? join(cwd2, "packages/ui") : cwd2;
30298
- const targetComponentsJson = join(targetPath, "components.json");
30299
- if (!existsSync(targetComponentsJson)) {
30300
- M2.error(`shadcn/ui is not configured in ${isMonorepo ? "packages/ui" : "this project"}.`);
30301
- M2.info("Run `bunkit init` with --ui-library shadcn to set up shadcn/ui first.");
30302
- process.exit(1);
31090
+ await writeFile(join(uiPath, "components.json"), JSON.stringify(componentsJson, null, 2));
31091
+ await writeFile(join(uiPath, "postcss.config.mjs"), `export default {
31092
+ plugins: {
31093
+ '@tailwindcss/postcss': {},
31094
+ },
31095
+ };
31096
+ `);
31097
+ const appsToScan = options.appsToScan || ["web", "platform"];
31098
+ const appSourcePaths = appsToScan.map((app) => `@source "../../../apps/${app}/src/**/*.{ts,tsx}";`);
31099
+ const baseColor = options.shadcnBaseColor || "zinc";
31100
+ const customRadius = options.shadcnRadius || "0.625rem";
31101
+ let globalsCss;
31102
+ if (useModernStyle) {
31103
+ const modernThemeCSS = generateModernThemeCSS(baseColor, customRadius);
31104
+ globalsCss = `@import "tailwindcss";
31105
+ @import "tw-animate-css";
31106
+ @import "shadcn/tailwind.css";
31107
+ ${appSourcePaths.join(`
31108
+ `)}
31109
+ @source "../**/*.{ts,tsx}";
31110
+
31111
+ @custom-variant dark (&:is(.dark *));
31112
+
31113
+ ${modernThemeCSS}
31114
+ `;
31115
+ } else {
31116
+ const theme = themes[baseColor] || themes.zinc;
31117
+ const themeCSS = generateThemeCSS(theme, customRadius);
31118
+ globalsCss = `@import "tailwindcss";
31119
+ ${appSourcePaths.join(`
31120
+ `)}
31121
+ @source "../**/*.{ts,tsx}";
31122
+
31123
+ ${themeCSS}
31124
+ `;
30303
31125
  }
30304
- let components = [];
30305
- if (options.all) {
30306
- const popularComponents = [
30307
- "button",
30308
- "card",
30309
- "input",
30310
- "label",
30311
- "textarea",
30312
- "select",
30313
- "checkbox",
30314
- "radio-group",
30315
- "switch",
30316
- "dialog",
30317
- "dropdown-menu",
30318
- "alert",
30319
- "badge",
30320
- "avatar",
30321
- "separator",
30322
- "skeleton",
30323
- "tabs",
30324
- "accordion",
30325
- "alert-dialog",
30326
- "aspect-ratio",
30327
- "breadcrumb",
30328
- "calendar",
30329
- "carousel",
30330
- "chart",
30331
- "collapsible",
30332
- "command",
30333
- "context-menu",
30334
- "drawer",
30335
- "form",
30336
- "hover-card",
30337
- "menubar",
30338
- "navigation-menu",
30339
- "popover",
30340
- "progress",
30341
- "scroll-area",
30342
- "sheet",
30343
- "slider",
30344
- "sonner",
30345
- "table",
30346
- "toast",
30347
- "toggle",
30348
- "tooltip"
30349
- ];
30350
- const selected = await fe({
30351
- message: "Select shadcn/ui components to install",
30352
- options: popularComponents.map((comp) => ({
30353
- value: comp,
31126
+ await writeFile(join(uiPath, "src/styles/globals.css"), globalsCss);
31127
+ await writeFile(join(uiPath, "src/lib/utils.ts"), `import { clsx, type ClassValue } from 'clsx';
31128
+ import { twMerge } from 'tailwind-merge';
31129
+
31130
+ export function cn(...inputs: ClassValue[]) {
31131
+ return twMerge(clsx(inputs));
31132
+ }
31133
+ `);
31134
+ await writeFile(join(uiPath, "src/components/index.ts"), `/**
31135
+ * UI Components
31136
+ *
31137
+ * Add shadcn/ui components using:
31138
+ * bunx shadcn@latest add button card dialog ...
31139
+ *
31140
+ * Then export them here for use across apps.
31141
+ */
31142
+
31143
+ // Export components as they are added
31144
+ // Example: export { Button } from './ui/button';
31145
+
31146
+ // Empty export to make this a valid ES module
31147
+ export {};
31148
+ `);
31149
+ await writeFile(join(uiPath, "src/hooks/index.ts"), `/**
31150
+ * Shared Hooks
31151
+ *
31152
+ * Custom React hooks shared across apps.
31153
+ */
31154
+
31155
+ // Export hooks as they are added
31156
+ // Example: export { useMediaQuery } from './use-media-query';
31157
+
31158
+ // Empty export to make this a valid ES module
31159
+ export {};
31160
+ `);
31161
+ await writeFile(join(uiPath, "src/index.ts"), `/**
31162
+ * @${options.scopeName}/ui - Shared UI Components
31163
+ *
31164
+ * This package provides:
31165
+ * - shadcn/ui components (add with: bunx shadcn@latest add <component>)
31166
+ * - Tailwind CSS v4 configuration
31167
+ * - Shared hooks and utilities
31168
+ *
31169
+ * Usage in apps:
31170
+ * - Import globals.css: import '@${options.scopeName}/ui/globals.css';
31171
+ * - Import components: import { Button } from '@${options.scopeName}/ui/components';
31172
+ * - Import utils: import { cn } from '@${options.scopeName}/ui/lib/utils';
31173
+ */
31174
+
31175
+ export * from './lib/utils';
31176
+ export * from './hooks';
31177
+ export * from './components';
31178
+ `);
31179
+ }
31180
+ async function buildTypesPackage(packagesPath, scopeName) {
31181
+ const typesPath = join(packagesPath, "types");
31182
+ await ensureDirectory(join(typesPath, "src"));
31183
+ const { writeTypesPackageJson: writeTypesPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
31184
+ await writeTypesPackageJson2(typesPath, scopeName);
31185
+ await writeFile(join(typesPath, "tsconfig.json"), JSON.stringify({
31186
+ extends: "../../tooling/typescript/library.json",
31187
+ compilerOptions: {
31188
+ rootDir: "./src",
31189
+ outDir: "./dist"
31190
+ },
31191
+ include: ["src/**/*"],
31192
+ exclude: ["node_modules"]
31193
+ }, null, 2));
31194
+ await writeFile(join(typesPath, "src/index.ts"), `/**
31195
+ * @${scopeName}/types - Shared TypeScript Types
31196
+ *
31197
+ * Define types that are shared across multiple packages/apps here.
31198
+ */
31199
+
31200
+ // Example types - replace with your actual types
31201
+
31202
+ export interface User {
31203
+ id: string;
31204
+ email: string;
31205
+ name?: string;
31206
+ createdAt: Date;
31207
+ updatedAt: Date;
31208
+ }
31209
+
31210
+ export interface ApiResponse<T> {
31211
+ success: boolean;
31212
+ data?: T;
31213
+ error?: {
31214
+ code: string;
31215
+ message: string;
31216
+ };
31217
+ }
31218
+
31219
+ export interface PaginatedResponse<T> extends ApiResponse<T[]> {
31220
+ pagination: {
31221
+ page: number;
31222
+ perPage: number;
31223
+ total: number;
31224
+ totalPages: number;
31225
+ };
31226
+ }
31227
+ `);
31228
+ }
31229
+ async function buildUtilsPackage(packagesPath, scopeName) {
31230
+ const utilsPath = join(packagesPath, "utils");
31231
+ await ensureDirectory(join(utilsPath, "src"));
31232
+ const { writeUtilsPackageJson: writeUtilsPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
31233
+ await writeUtilsPackageJson2(utilsPath, scopeName);
31234
+ await writeFile(join(utilsPath, "tsconfig.json"), JSON.stringify({
31235
+ extends: "../../tooling/typescript/library.json",
31236
+ compilerOptions: {
31237
+ rootDir: "./src",
31238
+ outDir: "./dist"
31239
+ },
31240
+ include: ["src/**/*"],
31241
+ exclude: ["node_modules"]
31242
+ }, null, 2));
31243
+ await writeFile(join(utilsPath, "src/index.ts"), `/**
31244
+ * @${scopeName}/utils - Shared Utilities
31245
+ *
31246
+ * Utility functions shared across packages and apps.
31247
+ */
31248
+
31249
+ /**
31250
+ * Format a date to a human-readable string
31251
+ */
31252
+ export function formatDate(date: Date | string, locale = 'en-US'): string {
31253
+ const d = typeof date === 'string' ? new Date(date) : date;
31254
+ return d.toLocaleDateString(locale, {
31255
+ year: 'numeric',
31256
+ month: 'long',
31257
+ day: 'numeric',
31258
+ });
31259
+ }
31260
+
31261
+ /**
31262
+ * Format a number as currency
31263
+ */
31264
+ export function formatCurrency(
31265
+ amount: number,
31266
+ currency = 'USD',
31267
+ locale = 'en-US'
31268
+ ): string {
31269
+ return new Intl.NumberFormat(locale, {
31270
+ style: 'currency',
31271
+ currency,
31272
+ }).format(amount);
31273
+ }
31274
+
31275
+ /**
31276
+ * Sleep for a specified number of milliseconds
31277
+ */
31278
+ export function sleep(ms: number): Promise<void> {
31279
+ return new Promise((resolve) => setTimeout(resolve, ms));
31280
+ }
31281
+
31282
+ /**
31283
+ * Safely parse JSON with a fallback value
31284
+ */
31285
+ export function safeJsonParse<T>(json: string, fallback: T): T {
31286
+ try {
31287
+ return JSON.parse(json) as T;
31288
+ } catch {
31289
+ return fallback;
31290
+ }
31291
+ }
31292
+
31293
+ /**
31294
+ * Generate a random ID
31295
+ */
31296
+ export function generateId(length = 12): string {
31297
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
31298
+ let result = '';
31299
+ for (let i = 0; i < length; i++) {
31300
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
31301
+ }
31302
+ return result;
31303
+ }
31304
+
31305
+ /**
31306
+ * Debounce a function
31307
+ */
31308
+ export function debounce<T extends (...args: unknown[]) => unknown>(
31309
+ func: T,
31310
+ wait: number
31311
+ ): (...args: Parameters<T>) => void {
31312
+ let timeout: ReturnType<typeof setTimeout> | null = null;
31313
+ return (...args: Parameters<T>) => {
31314
+ if (timeout) clearTimeout(timeout);
31315
+ timeout = setTimeout(() => func(...args), wait);
31316
+ };
31317
+ }
31318
+
31319
+ /**
31320
+ * Check if running on server
31321
+ * Uses a type-safe approach that works without DOM types
31322
+ */
31323
+ export function isServer(): boolean {
31324
+ return !(typeof window !== 'undefined' && window.document);
31325
+ }
31326
+
31327
+ /**
31328
+ * Check if running on client
31329
+ * Uses a type-safe approach that works without DOM types
31330
+ */
31331
+ export function isClient(): boolean {
31332
+ return typeof window !== 'undefined' && !!window.document;
31333
+ }
31334
+
31335
+ // Declare window for environments without DOM types
31336
+ declare const window: { document?: unknown } | undefined;
31337
+ `);
31338
+ }
31339
+
31340
+ // ../templates/src/builders/full-v2.ts
31341
+ async function buildFullPresetV2(projectPath, context) {
31342
+ const preset = PresetRegistry.get("nextjs-monorepo");
31343
+ if (!preset) {
31344
+ throw new Error("nextjs-monorepo preset not found in registry");
31345
+ }
31346
+ const scopeName = context.packageName;
31347
+ const directories = [
31348
+ "apps/web/src/app",
31349
+ "apps/web/src/components",
31350
+ "apps/web/src/lib",
31351
+ "apps/platform/src/app",
31352
+ "apps/platform/src/components",
31353
+ "apps/platform/src/lib",
31354
+ "apps/api/src/routes",
31355
+ "apps/api/src/middleware",
31356
+ "packages/ui",
31357
+ "packages/types",
31358
+ "packages/utils",
31359
+ "tooling/typescript"
31360
+ ];
31361
+ for (const dir of directories) {
31362
+ await ensureDirectory(join(projectPath, dir));
31363
+ }
31364
+ const catalog = preset.catalogEntries || {};
31365
+ await writeMonorepoRootPackageJson(projectPath, scopeName, catalog, {
31366
+ hasWeb: true,
31367
+ hasPlatform: true,
31368
+ hasApi: true,
31369
+ codeQuality: context.codeQuality === "biome" ? "biome" : "ultracite"
31370
+ });
31371
+ await writeFile(join(projectPath, "bunfig.toml"), generateBunfigContent(context));
31372
+ await writeNextjsAppPackageJson(join(projectPath, "apps/web"), scopeName, "web", { usesUi: true, usesTypes: true });
31373
+ await writeFile(join(projectPath, "apps/web/src/app/layout.tsx"), `import type { Metadata } from 'next';
31374
+ import '@${scopeName}/ui/globals.css';
31375
+
31376
+ export const metadata: Metadata = {
31377
+ title: '${context.projectName}',
31378
+ description: 'Enterprise SaaS built with bunkit',
31379
+ };
31380
+
31381
+ export default function RootLayout({
31382
+ children,
31383
+ }: {
31384
+ children: React.ReactNode;
31385
+ }) {
31386
+ return (
31387
+ <html lang="en">
31388
+ <body className="antialiased">{children}</body>
31389
+ </html>
31390
+ );
31391
+ }
31392
+ `);
31393
+ await writeFile(join(projectPath, "apps/web/src/app/page.tsx"), `import { Home, Rocket, Book } from 'iconoir-react';
31394
+
31395
+ export default function HomePage() {
31396
+ return (
31397
+ <main className="min-h-screen flex items-center justify-center bg-gradient-to-br from-background to-muted">
31398
+ <div className="text-center space-y-8 p-8 max-w-3xl">
31399
+ <div className="flex justify-center">
31400
+ <Home className="w-16 h-16 text-primary" />
31401
+ </div>
31402
+ <h1 className="text-5xl font-bold tracking-tight">
31403
+ Welcome to ${context.projectName}
31404
+ </h1>
31405
+ <p className="text-xl text-muted-foreground">
31406
+ Enterprise-grade SaaS built with Next.js 16, React 19, Hono, and Bun
31407
+ </p>
31408
+ <div className="flex gap-4 justify-center pt-4">
31409
+ <a
31410
+ href="/dashboard"
31411
+ className="inline-flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition font-medium"
31412
+ >
31413
+ <Rocket className="w-5 h-5" />
31414
+ Get Started
31415
+ </a>
31416
+ <a
31417
+ href="/docs"
31418
+ className="inline-flex items-center gap-2 px-6 py-3 bg-secondary text-secondary-foreground rounded-lg hover:bg-secondary/90 transition font-medium"
31419
+ >
31420
+ <Book className="w-5 h-5" />
31421
+ Documentation
31422
+ </a>
31423
+ </div>
31424
+ </div>
31425
+ </main>
31426
+ );
31427
+ }
31428
+ `);
31429
+ await writeFile(join(projectPath, "apps/web/next.config.ts"), `import type { NextConfig } from 'next';
31430
+
31431
+ const nextConfig: NextConfig = {
31432
+ transpilePackages: ['@${scopeName}/ui'],
31433
+ };
31434
+
31435
+ export default nextConfig;
31436
+ `);
31437
+ await writeFile(join(projectPath, "apps/web/tsconfig.json"), JSON.stringify({
31438
+ extends: "../../tooling/typescript/nextjs.json",
31439
+ compilerOptions: {
31440
+ paths: {
31441
+ "@/*": ["./src/*"]
31442
+ }
31443
+ },
31444
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
31445
+ exclude: ["node_modules"]
31446
+ }, null, 2));
31447
+ await writeFile(join(projectPath, "apps/web/postcss.config.mjs"), `export default {
31448
+ plugins: {
31449
+ '@tailwindcss/postcss': {},
31450
+ },
31451
+ };
31452
+ `);
31453
+ await writeNextjsAppPackageJson(join(projectPath, "apps/platform"), scopeName, "platform", { usesUi: true, usesTypes: true });
31454
+ await writeFile(join(projectPath, "apps/platform/src/app/layout.tsx"), `import type { Metadata } from 'next';
31455
+ import '@${scopeName}/ui/globals.css';
31456
+
31457
+ export const metadata: Metadata = {
31458
+ title: '${context.projectName} - Admin',
31459
+ description: 'Admin dashboard for ${context.projectName}',
31460
+ };
31461
+
31462
+ export default function RootLayout({
31463
+ children,
31464
+ }: {
31465
+ children: React.ReactNode;
31466
+ }) {
31467
+ return (
31468
+ <html lang="en">
31469
+ <body className="antialiased">{children}</body>
31470
+ </html>
31471
+ );
31472
+ }
31473
+ `);
31474
+ await writeFile(join(projectPath, "apps/platform/src/app/page.tsx"), `import { ViewGrid, User, Dollar, GraphUp } from 'iconoir-react';
31475
+
31476
+ export default function DashboardPage() {
31477
+ return (
31478
+ <main className="min-h-screen bg-background">
31479
+ <div className="max-w-7xl mx-auto py-12 px-4">
31480
+ <header className="mb-8 flex items-center gap-3">
31481
+ <ViewGrid className="w-8 h-8 text-primary" />
31482
+ <div>
31483
+ <h1 className="text-3xl font-bold">Admin Dashboard</h1>
31484
+ <p className="text-muted-foreground">
31485
+ Manage your ${context.projectName} platform
31486
+ </p>
31487
+ </div>
31488
+ </header>
31489
+
31490
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
31491
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31492
+ <div className="flex items-center gap-3 mb-2">
31493
+ <User className="w-5 h-5 text-blue-500" />
31494
+ <h2 className="text-lg font-semibold">Users</h2>
31495
+ </div>
31496
+ <p className="text-3xl font-bold">1,234</p>
31497
+ </div>
31498
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31499
+ <div className="flex items-center gap-3 mb-2">
31500
+ <Dollar className="w-5 h-5 text-green-500" />
31501
+ <h2 className="text-lg font-semibold">Revenue</h2>
31502
+ </div>
31503
+ <p className="text-3xl font-bold">$12,345</p>
31504
+ </div>
31505
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31506
+ <div className="flex items-center gap-3 mb-2">
31507
+ <GraphUp className="w-5 h-5 text-purple-500" />
31508
+ <h2 className="text-lg font-semibold">Active</h2>
31509
+ </div>
31510
+ <p className="text-3xl font-bold">567</p>
31511
+ </div>
31512
+ </div>
31513
+ </div>
31514
+ </main>
31515
+ );
31516
+ }
31517
+ `);
31518
+ await writeFile(join(projectPath, "apps/platform/next.config.ts"), `import type { NextConfig } from 'next';
31519
+
31520
+ const nextConfig: NextConfig = {
31521
+ transpilePackages: ['@${scopeName}/ui'],
31522
+ };
31523
+
31524
+ export default nextConfig;
31525
+ `);
31526
+ await writeFile(join(projectPath, "apps/platform/tsconfig.json"), JSON.stringify({
31527
+ extends: "../../tooling/typescript/nextjs.json",
31528
+ compilerOptions: {
31529
+ paths: {
31530
+ "@/*": ["./src/*"]
31531
+ }
31532
+ },
31533
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
31534
+ exclude: ["node_modules"]
31535
+ }, null, 2));
31536
+ await writeFile(join(projectPath, "apps/platform/postcss.config.mjs"), `export default {
31537
+ plugins: {
31538
+ '@tailwindcss/postcss': {},
31539
+ },
31540
+ };
31541
+ `);
31542
+ await writeHonoApiPackageJson(join(projectPath, "apps/api"), scopeName, {
31543
+ usesTypes: true
31544
+ });
31545
+ await writeFile(join(projectPath, "apps/api/src/index.ts"), `import { Hono } from 'hono';
31546
+ import { logger } from 'hono/logger';
31547
+ import { cors } from 'hono/cors';
31548
+
31549
+ const app = new Hono();
31550
+
31551
+ // Middleware
31552
+ app.use('*', logger());
31553
+ app.use('*', cors());
31554
+
31555
+ // Routes
31556
+ app.get('/', (context) => {
31557
+ return context.json({
31558
+ name: '${context.projectName} API',
31559
+ version: '1.0.0',
31560
+ timestamp: new Date().toISOString(),
31561
+ });
31562
+ });
31563
+
31564
+ app.get('/health', (context) => {
31565
+ return context.json({ status: 'ok' });
31566
+ });
31567
+
31568
+ app.get('/api/users', (context) => {
31569
+ return context.json({
31570
+ users: [
31571
+ { id: '1', email: 'john@example.com', name: 'John Doe' },
31572
+ { id: '2', email: 'jane@example.com', name: 'Jane Smith' },
31573
+ ],
31574
+ });
31575
+ });
31576
+
31577
+ // 404 handler
31578
+ app.notFound((context) => {
31579
+ return context.json({ error: 'Not found' }, 404);
31580
+ });
31581
+
31582
+ // Error handler
31583
+ app.onError((error, context) => {
31584
+ console.error('Error:', error);
31585
+ return context.json({ error: 'Internal server error' }, 500);
31586
+ });
31587
+
31588
+ // Start server with HMR
31589
+ const server = Bun.serve({
31590
+ fetch: app.fetch,
31591
+ port: 3002,
31592
+ development: {
31593
+ hmr: true,
31594
+ },
31595
+ });
31596
+
31597
+ console.log(\`\uD83D\uDE80 ${context.projectName} API running on \${server.url}\`);
31598
+
31599
+ export default app;
31600
+ `);
31601
+ await writeFile(join(projectPath, "apps/api/tsconfig.json"), JSON.stringify({
31602
+ extends: "../../tooling/typescript/api.json",
31603
+ compilerOptions: {
31604
+ types: ["bun-types"]
31605
+ },
31606
+ include: ["src/**/*"],
31607
+ exclude: ["node_modules"]
31608
+ }, null, 2));
31609
+ await buildUiPackage(join(projectPath, "packages"), {
31610
+ scopeName,
31611
+ shadcnStyle: context.shadcnStyle || "radix-maia",
31612
+ shadcnBase: context.shadcnBase || "radix",
31613
+ shadcnBaseColor: context.shadcnBaseColor || "zinc",
31614
+ shadcnIconLibrary: context.shadcnIconLibrary || "phosphor",
31615
+ shadcnMenuAccent: context.shadcnMenuAccent || "subtle",
31616
+ shadcnMenuColor: context.shadcnMenuColor || "default",
31617
+ shadcnRadius: context.shadcnRadius || "0.625rem",
31618
+ appsToScan: ["web", "platform"]
31619
+ });
31620
+ await buildTypesPackage(join(projectPath, "packages"), scopeName);
31621
+ await buildUtilsPackage(join(projectPath, "packages"), scopeName);
31622
+ await setupTooling(projectPath, context);
31623
+ await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify({
31624
+ extends: "./tooling/typescript/base.json",
31625
+ include: ["apps/*/src/**/*", "packages/*/src/**/*"],
31626
+ exclude: ["node_modules", "**/node_modules", "**/.next"]
31627
+ }, null, 2));
31628
+ if (context.codeQuality === "ultracite") {
31629
+ await setupUltracite(projectPath, context);
31630
+ } else {
31631
+ await setupBiome(projectPath, context);
31632
+ }
31633
+ if (context.docker) {
31634
+ await setupDocker(projectPath, context);
31635
+ }
31636
+ if (context.cicd) {
31637
+ await setupGitHubActions(projectPath, context);
31638
+ }
31639
+ await setupVSCodeDebug(projectPath, context, "full");
31640
+ await generateMonorepoReadme(projectPath, context, "nextjs");
31641
+ }
31642
+ // ../templates/src/shared/index.ts
31643
+ init_package_json();
31644
+ // ../templates/src/render.ts
31645
+ var import_ejs = __toESM(require_ejs(), 1);
31646
+ // src/commands/add/component.ts
31647
+ init_dist();
31648
+ async function getPackageName(cwd2) {
31649
+ try {
31650
+ const packageJsonPath = join(cwd2, "package.json");
31651
+ if (existsSync(packageJsonPath)) {
31652
+ const packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
31653
+ const name = packageJson.name;
31654
+ if (name?.endsWith("-monorepo")) {
31655
+ return name.replace("-monorepo", "");
31656
+ }
31657
+ return name || null;
31658
+ }
31659
+ } catch {}
31660
+ return null;
31661
+ }
31662
+ async function addComponentCommand(options = {}) {
31663
+ const cwd2 = options.cwd || process.cwd();
31664
+ const spinner = Y2();
31665
+ const componentsJsonPath = join(cwd2, "components.json");
31666
+ const isMonorepo = existsSync(join(cwd2, "packages/ui/components.json"));
31667
+ if (!existsSync(componentsJsonPath) && !isMonorepo) {
31668
+ M2.error("shadcn/ui is not configured in this project.");
31669
+ M2.info("Run `bunkit init` with --ui-library shadcn to set up shadcn/ui first.");
31670
+ process.exit(1);
31671
+ }
31672
+ const targetPath = isMonorepo ? join(cwd2, "packages/ui") : cwd2;
31673
+ const targetComponentsJson = join(targetPath, "components.json");
31674
+ if (!existsSync(targetComponentsJson)) {
31675
+ M2.error(`shadcn/ui is not configured in ${isMonorepo ? "packages/ui" : "this project"}.`);
31676
+ M2.info("Run `bunkit init` with --ui-library shadcn to set up shadcn/ui first.");
31677
+ process.exit(1);
31678
+ }
31679
+ let components = [];
31680
+ if (options.all) {
31681
+ const popularComponents = [
31682
+ "button",
31683
+ "card",
31684
+ "input",
31685
+ "label",
31686
+ "textarea",
31687
+ "select",
31688
+ "checkbox",
31689
+ "radio-group",
31690
+ "switch",
31691
+ "dialog",
31692
+ "dropdown-menu",
31693
+ "alert",
31694
+ "badge",
31695
+ "avatar",
31696
+ "separator",
31697
+ "skeleton",
31698
+ "tabs",
31699
+ "accordion",
31700
+ "alert-dialog",
31701
+ "aspect-ratio",
31702
+ "breadcrumb",
31703
+ "calendar",
31704
+ "carousel",
31705
+ "chart",
31706
+ "collapsible",
31707
+ "command",
31708
+ "context-menu",
31709
+ "drawer",
31710
+ "form",
31711
+ "hover-card",
31712
+ "menubar",
31713
+ "navigation-menu",
31714
+ "popover",
31715
+ "progress",
31716
+ "scroll-area",
31717
+ "sheet",
31718
+ "slider",
31719
+ "sonner",
31720
+ "table",
31721
+ "toast",
31722
+ "toggle",
31723
+ "tooltip"
31724
+ ];
31725
+ const selected = await fe({
31726
+ message: "Select shadcn/ui components to install",
31727
+ options: popularComponents.map((comp) => ({
31728
+ value: comp,
30354
31729
  label: comp
30355
31730
  })),
30356
31731
  required: true
@@ -31734,17 +33109,42 @@ async function enhancedInitCommand(options = {}) {
31734
33109
  if (!shadcnStyle && uiLibrary === "shadcn") {
31735
33110
  if (!isNonInteractive) {
31736
33111
  shadcnStyle = await ve({
31737
- message: "\uD83C\uDFA8 shadcn/ui component style",
33112
+ message: "\uD83C\uDFA8 shadcn/ui visual style",
31738
33113
  options: [
33114
+ {
33115
+ value: "radix-maia",
33116
+ label: "Maia (Recommended)",
33117
+ hint: "Modern, clean design with soft shadows and refined aesthetics"
33118
+ },
33119
+ {
33120
+ value: "radix-vega",
33121
+ label: "Vega",
33122
+ hint: "Bold, vibrant design with stronger colors and contrast"
33123
+ },
33124
+ {
33125
+ value: "radix-nova",
33126
+ label: "Nova",
33127
+ hint: "Minimalist design with subtle accents and clean lines"
33128
+ },
33129
+ {
33130
+ value: "radix-lyra",
33131
+ label: "Lyra",
33132
+ hint: "Elegant design with refined typography and spacing"
33133
+ },
33134
+ {
33135
+ value: "radix-mira",
33136
+ label: "Mira",
33137
+ hint: "Playful design with rounded elements and soft colors"
33138
+ },
31739
33139
  {
31740
33140
  value: "new-york",
31741
- label: "New York (Recommended)",
31742
- hint: "Modern design aesthetic - rounded corners, subtle shadows, clean look"
33141
+ label: "New York (Legacy)",
33142
+ hint: "Classic modern aesthetic - rounded corners, subtle shadows"
31743
33143
  },
31744
33144
  {
31745
33145
  value: "default",
31746
- label: "Default",
31747
- hint: "Classic design aesthetic - sharper edges, higher contrast, traditional look"
33146
+ label: "Default (Legacy)",
33147
+ hint: "Classic design - sharper edges, higher contrast"
31748
33148
  }
31749
33149
  ]
31750
33150
  });
@@ -31753,7 +33153,7 @@ async function enhancedInitCommand(options = {}) {
31753
33153
  process.exit(0);
31754
33154
  }
31755
33155
  } else {
31756
- shadcnStyle = "new-york";
33156
+ shadcnStyle = "radix-maia";
31757
33157
  }
31758
33158
  }
31759
33159
  let shadcnBaseColor = getOptionValue("BUNKIT_SHADCN_BASE_COLOR", options.shadcnBaseColor);
@@ -31822,6 +33222,122 @@ async function enhancedInitCommand(options = {}) {
31822
33222
  shadcnRadius = "0.625rem";
31823
33223
  }
31824
33224
  }
33225
+ let shadcnIconLibrary = getOptionValue("BUNKIT_SHADCN_ICON_LIBRARY", options.shadcnIconLibrary);
33226
+ const isModernShadcnStyle = shadcnStyle === "radix-maia" || shadcnStyle === "radix-vega" || shadcnStyle === "radix-nova" || shadcnStyle === "radix-lyra" || shadcnStyle === "radix-mira";
33227
+ if (!shadcnIconLibrary && uiLibrary === "shadcn") {
33228
+ if (!isNonInteractive) {
33229
+ shadcnIconLibrary = await ve({
33230
+ message: "\uD83D\uDD23 Icon library",
33231
+ options: [
33232
+ {
33233
+ value: "phosphor",
33234
+ label: isModernShadcnStyle ? "Phosphor Icons (Recommended)" : "Phosphor Icons",
33235
+ hint: "Modern icon library with consistent design - default for new shadcn/ui styles"
33236
+ },
33237
+ {
33238
+ value: "iconoir",
33239
+ label: !isModernShadcnStyle ? "Iconoir (Recommended)" : "Iconoir",
33240
+ hint: "Lightweight icons with great variety - alternative choice"
33241
+ },
33242
+ {
33243
+ value: "lucide",
33244
+ label: "Lucide",
33245
+ hint: "Classic choice - based on Feather icons, widely used"
33246
+ }
33247
+ ]
33248
+ });
33249
+ if (pD(shadcnIconLibrary)) {
33250
+ xe("Operation cancelled.");
33251
+ process.exit(0);
33252
+ }
33253
+ } else {
33254
+ shadcnIconLibrary = isModernShadcnStyle ? "phosphor" : "iconoir";
33255
+ }
33256
+ }
33257
+ let shadcnBase = getOptionValue("BUNKIT_SHADCN_BASE", options.shadcnBase);
33258
+ if (!shadcnBase && uiLibrary === "shadcn" && isModernShadcnStyle) {
33259
+ if (!isNonInteractive) {
33260
+ shadcnBase = await ve({
33261
+ message: "\uD83E\uDDF1 Component foundation",
33262
+ options: [
33263
+ {
33264
+ value: "radix",
33265
+ label: "Radix UI (Recommended)",
33266
+ hint: "Battle-tested accessibility primitives - industry standard"
33267
+ },
33268
+ {
33269
+ value: "base-ui",
33270
+ label: "Base UI",
33271
+ hint: "Modern alternative with similar API - newer, experimental"
33272
+ }
33273
+ ]
33274
+ });
33275
+ if (pD(shadcnBase)) {
33276
+ xe("Operation cancelled.");
33277
+ process.exit(0);
33278
+ }
33279
+ } else {
33280
+ shadcnBase = "radix";
33281
+ }
33282
+ } else if (!shadcnBase) {
33283
+ shadcnBase = "radix";
33284
+ }
33285
+ let shadcnMenuAccent = getOptionValue("BUNKIT_SHADCN_MENU_ACCENT", options.shadcnMenuAccent);
33286
+ if (!shadcnMenuAccent && uiLibrary === "shadcn" && isModernShadcnStyle) {
33287
+ if (!isNonInteractive) {
33288
+ shadcnMenuAccent = await ve({
33289
+ message: "\u2728 Menu accent style",
33290
+ options: [
33291
+ {
33292
+ value: "subtle",
33293
+ label: "Subtle (Recommended)",
33294
+ hint: "Soft accent colors - elegant and understated"
33295
+ },
33296
+ {
33297
+ value: "bold",
33298
+ label: "Bold",
33299
+ hint: "Strong accent colors - vibrant and eye-catching"
33300
+ }
33301
+ ]
33302
+ });
33303
+ if (pD(shadcnMenuAccent)) {
33304
+ xe("Operation cancelled.");
33305
+ process.exit(0);
33306
+ }
33307
+ } else {
33308
+ shadcnMenuAccent = "subtle";
33309
+ }
33310
+ } else if (!shadcnMenuAccent) {
33311
+ shadcnMenuAccent = "subtle";
33312
+ }
33313
+ let shadcnMenuColor = getOptionValue("BUNKIT_SHADCN_MENU_COLOR", options.shadcnMenuColor);
33314
+ if (!shadcnMenuColor && uiLibrary === "shadcn" && isModernShadcnStyle) {
33315
+ if (!isNonInteractive) {
33316
+ shadcnMenuColor = await ve({
33317
+ message: "\uD83C\uDFAF Menu color scheme",
33318
+ options: [
33319
+ {
33320
+ value: "default",
33321
+ label: "Default (Recommended)",
33322
+ hint: "Standard menu colors - balanced and consistent"
33323
+ },
33324
+ {
33325
+ value: "muted",
33326
+ label: "Muted",
33327
+ hint: "Subdued menu colors - softer and more subtle"
33328
+ }
33329
+ ]
33330
+ });
33331
+ if (pD(shadcnMenuColor)) {
33332
+ xe("Operation cancelled.");
33333
+ process.exit(0);
33334
+ }
33335
+ } else {
33336
+ shadcnMenuColor = "default";
33337
+ }
33338
+ } else if (!shadcnMenuColor) {
33339
+ shadcnMenuColor = "default";
33340
+ }
31825
33341
  let testing = getOptionValue("BUNKIT_TESTING", options.testing, "bun-test");
31826
33342
  if (!testing) {
31827
33343
  if (!isNonInteractive) {
@@ -32062,7 +33578,11 @@ async function enhancedInitCommand(options = {}) {
32062
33578
  envExample: true,
32063
33579
  pathAliases: true,
32064
33580
  shadcnStyle,
33581
+ shadcnBase,
32065
33582
  shadcnBaseColor,
33583
+ shadcnIconLibrary,
33584
+ shadcnMenuAccent,
33585
+ shadcnMenuColor,
32066
33586
  shadcnRadius,
32067
33587
  supabasePreset,
32068
33588
  supabaseFeatures,
@@ -32093,7 +33613,7 @@ async function enhancedInitCommand(options = {}) {
32093
33613
  case "full":
32094
33614
  case "monorepo-nextjs":
32095
33615
  case "nextjs-monorepo":
32096
- await buildFullPreset(projectPath, context);
33616
+ await buildFullPresetV2(projectPath, context);
32097
33617
  break;
32098
33618
  case "monorepo-bun":
32099
33619
  case "bun-monorepo":
@@ -32391,7 +33911,7 @@ Examples:
32391
33911
 
32392
33912
  For more information, visit: https://github.com/Arakiss/bunkit
32393
33913
  `);
32394
- 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 | nextjs | hono-api | bun-api | bun-fullstack | nextjs-monorepo | bun-monorepo | enterprise-monorepo").option("--database <database>", "Database option: postgres-drizzle | postgres-prisma | mysql-drizzle | mysql-prisma | supabase | supabase-drizzle | supabase-prisma | sqlite-drizzle | sqlite-prisma | none").option("--auth <auth>", "Authentication system: better-auth | nextauth | supabase | none").option("--redis", "Enable Redis cache/session store").option("--use-bun-secrets", "Use Bun.secrets API instead of .env files").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)").option("--save-preset <name>", "Save current configuration as a custom preset").option("--load-preset <name>", "Load configuration from a custom preset").addHelpText("after", `
33914
+ 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 | nextjs | hono-api | bun-api | bun-fullstack | nextjs-monorepo | bun-monorepo | enterprise-monorepo").option("--database <database>", "Database option: postgres-drizzle | postgres-prisma | mysql-drizzle | mysql-prisma | supabase | supabase-drizzle | supabase-prisma | sqlite-drizzle | sqlite-prisma | none").option("--auth <auth>", "Authentication system: better-auth | nextauth | supabase | none").option("--redis", "Enable Redis cache/session store").option("--use-bun-secrets", "Use Bun.secrets API instead of .env files").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 style: radix-maia | radix-vega | radix-nova | radix-lyra | radix-mira | new-york | default").option("--shadcn-base <base>", "shadcn/ui component foundation: radix | base-ui").option("--shadcn-base-color <color>", "shadcn/ui base color theme: zinc | slate | stone | gray | neutral").option("--shadcn-icon-library <library>", "shadcn/ui icon library: phosphor | lucide | iconoir").option("--shadcn-menu-accent <accent>", "shadcn/ui menu accent style: subtle | bold").option("--shadcn-menu-color <color>", "shadcn/ui menu color: default | muted").option("--shadcn-radius <radius>", "shadcn/ui border radius (CSS value, e.g., 0.5rem, 0.625rem)").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)").option("--save-preset <name>", "Save current configuration as a custom preset").option("--load-preset <name>", "Load configuration from a custom preset").addHelpText("after", `
32395
33915
  Examples:
32396
33916
  $ bunkit init Interactive project creation
32397
33917
  $ bunkit init --name my-app --preset nextjs Quick web app creation