create-cronus-stack 0.6.0 → 0.6.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.
package/dist/scaffold.js CHANGED
@@ -41,6 +41,79 @@ function cronusUiPaths(config) {
41
41
  function usesCronusUi(config) {
42
42
  return single(config, "ui") === "ui-cronus";
43
43
  }
44
+ const SQL_DATABASES = new Set(["db-sqlite", "db-postgres", "db-mysql"]);
45
+ const HOSTED_DB_SETUPS = new Set([
46
+ "dbsetup-turso",
47
+ "dbsetup-neon",
48
+ "dbsetup-supabase",
49
+ "dbsetup-planetscale",
50
+ "dbsetup-d1",
51
+ "dbsetup-atlas",
52
+ ]);
53
+ function sqlDialect(config) {
54
+ switch (single(config, "database")) {
55
+ case "db-sqlite":
56
+ return "sqlite";
57
+ case "db-postgres":
58
+ return "postgresql";
59
+ case "db-mysql":
60
+ return "mysql";
61
+ default:
62
+ return undefined;
63
+ }
64
+ }
65
+ function emitsDrizzle(config) {
66
+ return (single(config, "web") === "web-next" &&
67
+ single(config, "orm") === "orm-drizzle" &&
68
+ SQL_DATABASES.has(single(config, "database") ?? ""));
69
+ }
70
+ function emitsBetterAuth(config) {
71
+ return emitsDrizzle(config) && single(config, "auth") === "auth-better-auth";
72
+ }
73
+ function usesImportAlias(config) {
74
+ return single(config, "importAlias") === "import-alias";
75
+ }
76
+ function sourceRoot(config) {
77
+ return single(config, "structure") === "structure-root" ? "" : "src/";
78
+ }
79
+ function dbDir(config) {
80
+ return `${sourceRoot(config)}db`;
81
+ }
82
+ function libDir(config) {
83
+ return `${sourceRoot(config)}lib`;
84
+ }
85
+ function defaultDatabaseUrl(config) {
86
+ switch (single(config, "database")) {
87
+ case "db-sqlite":
88
+ return "file:./data/app.db";
89
+ case "db-postgres":
90
+ return "postgres://postgres:postgres@localhost:5432/app";
91
+ case "db-mysql":
92
+ return "mysql://root:password@localhost:3306/app";
93
+ default:
94
+ return undefined;
95
+ }
96
+ }
97
+ function betterAuthProvider(config) {
98
+ switch (single(config, "database")) {
99
+ case "db-postgres":
100
+ return "pg";
101
+ case "db-mysql":
102
+ return "mysql";
103
+ default:
104
+ return "sqlite";
105
+ }
106
+ }
107
+ function dbModuleImport(config, subpath) {
108
+ const target = subpath ? `db/${subpath}` : "db";
109
+ return usesImportAlias(config) ? `@/${target}` : `../${target}`;
110
+ }
111
+ function authModuleImport(config) {
112
+ return usesImportAlias(config) ? "@/lib/auth" : "../../../../lib/auth";
113
+ }
114
+ function scriptCommand(pm, script) {
115
+ return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
116
+ }
44
117
  function packageJson(projectName, config) {
45
118
  const isNext = single(config, "web") === "web-next";
46
119
  const isCronusUi = usesCronusUi(config);
@@ -70,6 +143,25 @@ function packageJson(projectName, config) {
70
143
  add(devDeps, "@commitlint/cli", "^20.2.0");
71
144
  add(devDeps, "@commitlint/config-conventional", "^20.2.0");
72
145
  }
146
+ if (emitsDrizzle(config)) {
147
+ add(deps, "drizzle-orm", "^0.45.2");
148
+ add(devDeps, "drizzle-kit", "^0.31.10");
149
+ switch (single(config, "database")) {
150
+ case "db-sqlite":
151
+ add(deps, "better-sqlite3", "^13.0.3");
152
+ add(devDeps, "@types/better-sqlite3", "^9.6.0");
153
+ break;
154
+ case "db-postgres":
155
+ add(deps, "postgres", "^3.4.9");
156
+ break;
157
+ case "db-mysql":
158
+ add(deps, "mysql2", "^3.24.2");
159
+ break;
160
+ }
161
+ }
162
+ if (emitsBetterAuth(config)) {
163
+ add(deps, "better-auth", "^1.7.2");
164
+ }
73
165
  const scripts = isNext
74
166
  ? {
75
167
  dev: "next dev",
@@ -86,7 +178,12 @@ function packageJson(projectName, config) {
86
178
  scripts.lint = "biome check .";
87
179
  scripts.format = "biome format --write .";
88
180
  }
89
- if (single(config, "database") !== "db-none") {
181
+ if (emitsDrizzle(config)) {
182
+ scripts["db:push"] = "drizzle-kit push";
183
+ scripts["db:generate"] = "drizzle-kit generate";
184
+ scripts["db:studio"] = "drizzle-kit studio";
185
+ }
186
+ else if (single(config, "database") !== "db-none") {
90
187
  scripts["db:push"] = 'echo "Configure the selected database/ORM before syncing schema."';
91
188
  }
92
189
  return `${JSON.stringify({
@@ -303,8 +400,12 @@ function basicIndex(projectName) {
303
400
  }
304
401
  function readme(projectName, config, unsupported) {
305
402
  const pm = packageManagerFromConfig(config);
306
- const dev = pm === "npm" ? "npm run dev" : `${pm} dev`;
307
403
  const install = pm === "yarn" ? "yarn" : `${pm} install`;
404
+ const runLines = [install];
405
+ if (emitsDrizzle(config) && single(config, "database") === "db-sqlite") {
406
+ runLines.push(scriptCommand(pm, "db:push"));
407
+ }
408
+ runLines.push(scriptCommand(pm, "dev"));
308
409
  return `# ${projectName}
309
410
 
310
411
  Generated by \`create-cronus-stack\`.
@@ -315,8 +416,7 @@ conventions, AI capabilities, guardrails, and Definition of Done.
315
416
  ## Run
316
417
 
317
418
  \`\`\`sh
318
- ${install}
319
- ${dev}
419
+ ${runLines.join("\n")}
320
420
  \`\`\`
321
421
 
322
422
  ## Generated artifacts
@@ -330,16 +430,42 @@ ${unsupported.length ? `## Manual follow-up\n\n${unsupported.map((item) => `- ${
330
430
  }
331
431
  function envExample(config) {
332
432
  const lines = [];
333
- if (single(config, "database") !== "db-none")
334
- lines.push("DATABASE_URL=");
335
- if (single(config, "auth") !== "auth-none")
433
+ if (single(config, "database") !== "db-none") {
434
+ const url = emitsDrizzle(config) ? (defaultDatabaseUrl(config) ?? "") : "";
435
+ lines.push(`DATABASE_URL=${url}`);
436
+ }
437
+ if (emitsBetterAuth(config)) {
438
+ lines.push("BETTER_AUTH_SECRET=change-me-to-a-32-character-secret");
439
+ lines.push("BETTER_AUTH_URL=http://localhost:3000");
440
+ }
441
+ else if (single(config, "auth") !== "auth-none") {
336
442
  lines.push("AUTH_SECRET=");
443
+ }
337
444
  if (single(config, "payments") !== "pay-none") {
338
445
  lines.push("PAYMENTS_SECRET_KEY=");
339
446
  lines.push("PAYMENTS_WEBHOOK_SECRET=");
340
447
  }
341
448
  return lines.length ? `${lines.join("\n")}\n` : undefined;
342
449
  }
450
+ function gitignore(config) {
451
+ const lines = ["node_modules", ".next", "dist", ".env*", "!.env.example", ".DS_Store"];
452
+ if (emitsDrizzle(config)) {
453
+ lines.push("*.db", "data/", "drizzle/");
454
+ }
455
+ return `${lines.join("\n")}\n`;
456
+ }
457
+ function nextConfigMjs(config) {
458
+ const body = emitsDrizzle(config) && single(config, "database") === "db-sqlite"
459
+ ? `{
460
+ serverExternalPackages: ["better-sqlite3"],
461
+ }`
462
+ : "{}";
463
+ return `/** @type {import('next').NextConfig} */
464
+ const nextConfig = ${body};
465
+
466
+ export default nextConfig;
467
+ `;
468
+ }
343
469
  function assistantIds(config) {
344
470
  const picked = new Set();
345
471
  for (const id of multi(config, "assistants")) {
@@ -354,6 +480,309 @@ function assistantIds(config) {
354
480
  }
355
481
  return [...picked];
356
482
  }
483
+ const CATALOG_SKILL_TO_KIT = {
484
+ "skill-ui-add": "ui-add",
485
+ "skill-theme": "theme",
486
+ "skill-compose": "compose",
487
+ "skill-upgrade": "upgrade",
488
+ "skill-code-review": "code-review",
489
+ "skill-ship-pr": "ship-pr",
490
+ "skill-evidence-check": "evidence-check",
491
+ };
492
+ /** Catalog skill ids → AI Kit skills. Empty selection keeps the kit default. */
493
+ function kitSkillsFromConfig(config) {
494
+ const selected = multi(config, "skills");
495
+ if (selected.length === 0)
496
+ return undefined;
497
+ const mapped = [];
498
+ for (const id of selected) {
499
+ const skill = CATALOG_SKILL_TO_KIT[id];
500
+ if (skill)
501
+ mapped.push(skill);
502
+ }
503
+ return mapped;
504
+ }
505
+ function drizzleConfig(config) {
506
+ const dialect = sqlDialect(config) ?? "sqlite";
507
+ const fallback = defaultDatabaseUrl(config) ?? "file:./data/app.db";
508
+ return `import { defineConfig } from "drizzle-kit";
509
+
510
+ export default defineConfig({
511
+ dialect: "${dialect}",
512
+ schema: "./${dbDir(config)}/schema.ts",
513
+ out: "./drizzle",
514
+ dbCredentials: { url: process.env.DATABASE_URL ?? "${fallback}" },
515
+ });
516
+ `;
517
+ }
518
+ function sqliteAuthTables() {
519
+ return `
520
+ export const user = sqliteTable("user", {
521
+ id: text("id").primaryKey(),
522
+ name: text("name").notNull(),
523
+ email: text("email").notNull().unique(),
524
+ emailVerified: integer("email_verified", { mode: "boolean" }).notNull(),
525
+ image: text("image"),
526
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
527
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
528
+ });
529
+
530
+ export const session = sqliteTable("session", {
531
+ id: text("id").primaryKey(),
532
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
533
+ token: text("token").notNull().unique(),
534
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
535
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
536
+ ipAddress: text("ip_address"),
537
+ userAgent: text("user_agent"),
538
+ userId: text("user_id")
539
+ .notNull()
540
+ .references(() => user.id, { onDelete: "cascade" }),
541
+ });
542
+
543
+ export const account = sqliteTable("account", {
544
+ id: text("id").primaryKey(),
545
+ issuer: text("issuer").notNull(),
546
+ accountId: text("account_id").notNull(),
547
+ providerId: text("provider_id").notNull(),
548
+ userId: text("user_id")
549
+ .notNull()
550
+ .references(() => user.id, { onDelete: "cascade" }),
551
+ accessToken: text("access_token"),
552
+ refreshToken: text("refresh_token"),
553
+ idToken: text("id_token"),
554
+ accessTokenExpiresAt: integer("access_token_expires_at", { mode: "timestamp" }),
555
+ refreshTokenExpiresAt: integer("refresh_token_expires_at", { mode: "timestamp" }),
556
+ scope: text("scope"),
557
+ password: text("password"),
558
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
559
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
560
+ });
561
+
562
+ export const verification = sqliteTable("verification", {
563
+ id: text("id").primaryKey(),
564
+ identifier: text("identifier").notNull(),
565
+ value: text("value").notNull(),
566
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
567
+ createdAt: integer("created_at", { mode: "timestamp" }),
568
+ updatedAt: integer("updated_at", { mode: "timestamp" }),
569
+ });
570
+ `;
571
+ }
572
+ function pgAuthTables() {
573
+ return `
574
+ export const user = pgTable("user", {
575
+ id: text("id").primaryKey(),
576
+ name: text("name").notNull(),
577
+ email: text("email").notNull().unique(),
578
+ emailVerified: boolean("email_verified").notNull(),
579
+ image: text("image"),
580
+ createdAt: timestamp("created_at").notNull(),
581
+ updatedAt: timestamp("updated_at").notNull(),
582
+ });
583
+
584
+ export const session = pgTable("session", {
585
+ id: text("id").primaryKey(),
586
+ expiresAt: timestamp("expires_at").notNull(),
587
+ token: text("token").notNull().unique(),
588
+ createdAt: timestamp("created_at").notNull(),
589
+ updatedAt: timestamp("updated_at").notNull(),
590
+ ipAddress: text("ip_address"),
591
+ userAgent: text("user_agent"),
592
+ userId: text("user_id")
593
+ .notNull()
594
+ .references(() => user.id, { onDelete: "cascade" }),
595
+ });
596
+
597
+ export const account = pgTable("account", {
598
+ id: text("id").primaryKey(),
599
+ issuer: text("issuer").notNull(),
600
+ accountId: text("account_id").notNull(),
601
+ providerId: text("provider_id").notNull(),
602
+ userId: text("user_id")
603
+ .notNull()
604
+ .references(() => user.id, { onDelete: "cascade" }),
605
+ accessToken: text("access_token"),
606
+ refreshToken: text("refresh_token"),
607
+ idToken: text("id_token"),
608
+ accessTokenExpiresAt: timestamp("access_token_expires_at"),
609
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
610
+ scope: text("scope"),
611
+ password: text("password"),
612
+ createdAt: timestamp("created_at").notNull(),
613
+ updatedAt: timestamp("updated_at").notNull(),
614
+ });
615
+
616
+ export const verification = pgTable("verification", {
617
+ id: text("id").primaryKey(),
618
+ identifier: text("identifier").notNull(),
619
+ value: text("value").notNull(),
620
+ expiresAt: timestamp("expires_at").notNull(),
621
+ createdAt: timestamp("created_at"),
622
+ updatedAt: timestamp("updated_at"),
623
+ });
624
+ `;
625
+ }
626
+ function mysqlAuthTables() {
627
+ return `
628
+ export const user = mysqlTable("user", {
629
+ id: varchar("id", { length: 36 }).primaryKey(),
630
+ name: varchar("name", { length: 255 }).notNull(),
631
+ email: varchar("email", { length: 255 }).notNull().unique(),
632
+ emailVerified: boolean("email_verified").notNull(),
633
+ image: text("image"),
634
+ createdAt: timestamp("created_at").notNull(),
635
+ updatedAt: timestamp("updated_at").notNull(),
636
+ });
637
+
638
+ export const session = mysqlTable("session", {
639
+ id: varchar("id", { length: 36 }).primaryKey(),
640
+ expiresAt: timestamp("expires_at").notNull(),
641
+ token: varchar("token", { length: 255 }).notNull().unique(),
642
+ createdAt: timestamp("created_at").notNull(),
643
+ updatedAt: timestamp("updated_at").notNull(),
644
+ ipAddress: text("ip_address"),
645
+ userAgent: text("user_agent"),
646
+ userId: varchar("user_id", { length: 36 })
647
+ .notNull()
648
+ .references(() => user.id, { onDelete: "cascade" }),
649
+ });
650
+
651
+ export const account = mysqlTable("account", {
652
+ id: varchar("id", { length: 36 }).primaryKey(),
653
+ issuer: varchar("issuer", { length: 255 }).notNull(),
654
+ accountId: varchar("account_id", { length: 255 }).notNull(),
655
+ providerId: varchar("provider_id", { length: 255 }).notNull(),
656
+ userId: varchar("user_id", { length: 36 })
657
+ .notNull()
658
+ .references(() => user.id, { onDelete: "cascade" }),
659
+ accessToken: text("access_token"),
660
+ refreshToken: text("refresh_token"),
661
+ idToken: text("id_token"),
662
+ accessTokenExpiresAt: timestamp("access_token_expires_at"),
663
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
664
+ scope: text("scope"),
665
+ password: text("password"),
666
+ createdAt: timestamp("created_at").notNull(),
667
+ updatedAt: timestamp("updated_at").notNull(),
668
+ });
669
+
670
+ export const verification = mysqlTable("verification", {
671
+ id: varchar("id", { length: 36 }).primaryKey(),
672
+ identifier: varchar("identifier", { length: 255 }).notNull(),
673
+ value: text("value").notNull(),
674
+ expiresAt: timestamp("expires_at").notNull(),
675
+ createdAt: timestamp("created_at"),
676
+ updatedAt: timestamp("updated_at"),
677
+ });
678
+ `;
679
+ }
680
+ function drizzleSchema(config) {
681
+ const withAuth = emitsBetterAuth(config);
682
+ switch (sqlDialect(config)) {
683
+ case "postgresql": {
684
+ const imports = withAuth
685
+ ? 'import { boolean, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";'
686
+ : 'import { integer, pgTable, text } from "drizzle-orm/pg-core";';
687
+ return `${imports}
688
+
689
+ export const items = pgTable("items", {
690
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
691
+ title: text("title").notNull(),
692
+ });
693
+ ${withAuth ? pgAuthTables() : ""}`;
694
+ }
695
+ case "mysql": {
696
+ const imports = withAuth
697
+ ? 'import { boolean, int, mysqlTable, text, timestamp, varchar } from "drizzle-orm/mysql-core";'
698
+ : 'import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";';
699
+ return `${imports}
700
+
701
+ export const items = mysqlTable("items", {
702
+ id: int("id").autoincrement().primaryKey(),
703
+ title: varchar("title", { length: 255 }).notNull(),
704
+ });
705
+ ${withAuth ? mysqlAuthTables() : ""}`;
706
+ }
707
+ default:
708
+ return `import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
709
+
710
+ export const items = sqliteTable("items", {
711
+ id: integer("id").primaryKey({ autoIncrement: true }),
712
+ title: text("title").notNull(),
713
+ });
714
+ ${withAuth ? sqliteAuthTables() : ""}`;
715
+ }
716
+ }
717
+ function drizzleClient(config) {
718
+ const fallback = defaultDatabaseUrl(config) ?? "file:./data/app.db";
719
+ switch (sqlDialect(config)) {
720
+ case "postgresql":
721
+ return `import { drizzle } from "drizzle-orm/postgres-js";
722
+ import postgres from "postgres";
723
+ import * as schema from "./schema";
724
+
725
+ const url = process.env.DATABASE_URL ?? "${fallback}";
726
+ const client = postgres(url);
727
+
728
+ export const db = drizzle(client, { schema });
729
+ `;
730
+ case "mysql":
731
+ return `import { drizzle } from "drizzle-orm/mysql2";
732
+ import mysql from "mysql2/promise";
733
+ import * as schema from "./schema";
734
+
735
+ const url = process.env.DATABASE_URL ?? "${fallback}";
736
+ const pool = mysql.createPool(url);
737
+
738
+ export const db = drizzle(pool, { schema, mode: "default" });
739
+ `;
740
+ default:
741
+ return `import { mkdirSync } from "node:fs";
742
+ import { dirname } from "node:path";
743
+ import Database from "better-sqlite3";
744
+ import { drizzle } from "drizzle-orm/better-sqlite3";
745
+ import * as schema from "./schema";
746
+
747
+ const url = process.env.DATABASE_URL ?? "${fallback}";
748
+ const fileFromUrl = url.startsWith("file:") ? url.slice("file:".length) : url;
749
+ mkdirSync(dirname(fileFromUrl) || ".", { recursive: true });
750
+ const sqlite = new Database(fileFromUrl);
751
+
752
+ export const db = drizzle(sqlite, { schema });
753
+ `;
754
+ }
755
+ }
756
+ function betterAuthServer(config) {
757
+ const provider = betterAuthProvider(config);
758
+ const dbImport = dbModuleImport(config);
759
+ const schemaImport = dbModuleImport(config, "schema");
760
+ return `import { betterAuth } from "better-auth";
761
+ import { drizzleAdapter } from "better-auth/adapters/drizzle";
762
+ import { db } from "${dbImport}";
763
+ import * as schema from "${schemaImport}";
764
+
765
+ export const auth = betterAuth({
766
+ database: drizzleAdapter(db, { provider: "${provider}", schema }),
767
+ emailAndPassword: { enabled: true },
768
+ secret: process.env.BETTER_AUTH_SECRET,
769
+ baseURL: process.env.BETTER_AUTH_URL,
770
+ });
771
+ `;
772
+ }
773
+ function betterAuthClient() {
774
+ return `import { createAuthClient } from "better-auth/react";
775
+
776
+ export const authClient = createAuthClient();
777
+ `;
778
+ }
779
+ function betterAuthRoute(config) {
780
+ return `import { auth } from "${authModuleImport(config)}";
781
+ import { toNextJsHandler } from "better-auth/next-js";
782
+
783
+ export const { GET, POST } = toNextJsHandler(auth);
784
+ `;
785
+ }
357
786
  function unsupportedNotes(config) {
358
787
  const notes = [];
359
788
  if (single(config, "web") !== "web-next") {
@@ -367,10 +796,15 @@ function unsupportedNotes(config) {
367
796
  single(config, "backend") !== "backend-fullstack-next") {
368
797
  notes.push("Add the selected dedicated backend service described in KICKOFF.md.");
369
798
  }
370
- if (single(config, "database") !== "db-none") {
799
+ if (emitsDrizzle(config)) {
800
+ if (HOSTED_DB_SETUPS.has(single(config, "dbSetup") ?? "")) {
801
+ notes.push("Configure the selected hosted database provider; generated Drizzle files use a local DATABASE_URL.");
802
+ }
803
+ }
804
+ else if (single(config, "database") !== "db-none") {
371
805
  notes.push("Wire the selected database/ORM/provider before running db:push.");
372
806
  }
373
- if (single(config, "auth") !== "auth-none") {
807
+ if (!emitsBetterAuth(config) && single(config, "auth") !== "auth-none") {
374
808
  notes.push("Implement the selected auth provider and protect mutating routes.");
375
809
  }
376
810
  if (single(config, "payments") !== "pay-none") {
@@ -388,9 +822,6 @@ function unsupportedNotes(config) {
388
822
  if (mcpIds.includes("mcp-cronus-ui") && !usesCronusUi(config)) {
389
823
  notes.push("The cronus-ui MCP server is not generated for stacks that do not use Cronus UI.");
390
824
  }
391
- if (multi(config, "skills").length > 0) {
392
- notes.push("Install the selected agent skill packs in your agent environment; KICKOFF.md records the choices but the scaffold does not install external skills.");
393
- }
394
825
  const unsupportedAddons = multi(config, "addons").filter((id) => id !== "addon-biome");
395
826
  if (unsupportedAddons.length > 0) {
396
827
  notes.push("Wire the selected addons manually unless noted otherwise; this generator currently scaffolds Biome config and records the rest in KICKOFF.md.");
@@ -418,7 +849,7 @@ export function scaffoldStack(options) {
418
849
  emit("README.md", readme(projectName, config, unsupported));
419
850
  emit("KICKOFF.md", generateKickoff(config, projectName, catalog));
420
851
  emit("stack.json", `${generateStackJson(config, projectName)}\n`);
421
- emit(".gitignore", "node_modules\n.next\ndist\n.env*\n!.env.example\n.DS_Store\n");
852
+ emit(".gitignore", gitignore(config));
422
853
  emit("tsconfig.json", tsconfig(config));
423
854
  emit(".env.example", envExample(config));
424
855
  if (single(config, "commitStyle") === "commit-conventional") {
@@ -429,7 +860,7 @@ export function scaffoldStack(options) {
429
860
  }
430
861
  if (single(config, "web") === "web-next") {
431
862
  const isCronusUi = usesCronusUi(config);
432
- emit("next.config.mjs", "/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default nextConfig;\n");
863
+ emit("next.config.mjs", nextConfigMjs(config));
433
864
  const app = appDir(config);
434
865
  if (isCronusUi) {
435
866
  emit("postcss.config.mjs", 'export default { plugins: { "@tailwindcss/postcss": {} } };\n');
@@ -448,6 +879,16 @@ export function scaffoldStack(options) {
448
879
  emit(`${app}/layout.tsx`, neutralLayoutTsx(projectName));
449
880
  emit(`${app}/page.tsx`, neutralPageTsx(config));
450
881
  }
882
+ if (emitsDrizzle(config)) {
883
+ emit("drizzle.config.ts", drizzleConfig(config));
884
+ emit(`${dbDir(config)}/schema.ts`, drizzleSchema(config));
885
+ emit(`${dbDir(config)}/index.ts`, drizzleClient(config));
886
+ }
887
+ if (emitsBetterAuth(config)) {
888
+ emit(`${libDir(config)}/auth.ts`, betterAuthServer(config));
889
+ emit(`${libDir(config)}/auth-client.ts`, betterAuthClient());
890
+ emit(`${app}/api/auth/[...all]/route.ts`, betterAuthRoute(config));
891
+ }
451
892
  }
452
893
  else {
453
894
  emit("src/index.ts", basicIndex(projectName));
@@ -461,6 +902,7 @@ export function scaffoldStack(options) {
461
902
  name: projectName,
462
903
  assistants,
463
904
  preset: "standard",
905
+ skills: kitSkillsFromConfig(config),
464
906
  includeCronusUi: isCronusUi,
465
907
  cronusUiMcp,
466
908
  });
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const CREATE_STACK_VERSION = "0.6.0";
1
+ export declare const CREATE_STACK_VERSION = "0.6.1";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const CREATE_STACK_VERSION = "0.6.0";
1
+ export const CREATE_STACK_VERSION = "0.6.1";
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-cronus-stack",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Scaffold a Cronus stack from the Cronus Stack Builder contract: app files, stack.json, KICKOFF.md, and optional AI Kit.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,8 +44,8 @@
44
44
  "prepublishOnly": "tsc -p tsconfig.json"
45
45
  },
46
46
  "dependencies": {
47
- "@cronus-ui/ai-kit": "0.6.0",
48
- "@cronus-ui/stack": "0.6.0"
47
+ "@cronus-ui/ai-kit": "0.6.1",
48
+ "@cronus-ui/stack": "0.6.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^22.10.0",