create-payload-stack 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +141 -53
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,11 +6,11 @@ Scaffold a SaaS on Payload CMS in one command.
6
6
  npx create-payload-stack@latest
7
7
  ```
8
8
 
9
- Nine prompts: project name, database (PostgreSQL, MongoDB, SQLite, Vercel Postgres), connection string, sign-in methods, organizations, billing, media storage (skip for local disk, or Vercel Blob, AWS S3, Cloudflare R2, Azure Blob Storage, Google Cloud Storage, Uploadthing), transactional emails (edit copy in the Payload admin, or keep React Email components in code) and cookie consent (banner with audited legal pages, or plain legal pages). The CLI downloads [Payload Stack](https://www.payloadstack.com), writes your answers into `src/stack.config.ts`, swaps the Payload database adapter, wires the storage adapter into `payload.config.ts`, generates `.env` with fresh secrets, installs dependencies and initializes git.
9
+ Twelve prompts: project name, database (PostgreSQL, MongoDB, SQLite, Vercel Postgres), connection string, sign-in methods, organizations, billing, media storage (skip for local disk, or Vercel Blob, AWS S3, Cloudflare R2, Azure Blob Storage, Google Cloud Storage, Uploadthing), transactional emails (edit copy in the Payload admin, or keep React Email components in code) cookie consent (banner with audited legal pages, or plain legal pages), scheduled actions and what runs them, and the coding agents you use (Claude Code, Codex, Cursor: task skills and MCP servers on top of `AGENTS.md`). The CLI downloads [Payload Stack](https://www.payloadstack.com), writes your answers into `src/stack.config.ts`, swaps the Payload database adapter, wires the storage adapter into `payload.config.ts`, generates `.env` with fresh secrets, installs dependencies and initializes git.
10
10
 
11
11
  ```bash
12
12
  # non-interactive
13
- npx create-payload-stack@latest ridgeline -d postgres --auth email-password,magic-link,passkey --social github --billing organization --storage vercel-blob --emails --consent -y
13
+ npx create-payload-stack@latest ridgeline -d postgres --auth email-password,magic-link,passkey --social github --billing organization --storage vercel-blob --emails --consent --agents claude,cursor -y
14
14
  ```
15
15
 
16
16
  Run `npx create-payload-stack@latest --help` for every flag. Documentation: https://payload.solutions/docs/payload-stack
package/dist/index.js CHANGED
@@ -8,6 +8,74 @@ import pc3 from "picocolors";
8
8
  import { parseArgs } from "util";
9
9
  import pc from "picocolors";
10
10
 
11
+ // src/agents.ts
12
+ import { cp, mkdir, rm, writeFile } from "fs/promises";
13
+ import { existsSync } from "fs";
14
+ import path from "path";
15
+ var AGENT_KEYS = ["claude", "codex", "cursor"];
16
+ var AGENT_CHOICES = {
17
+ claude: { label: "Claude Code", hint: "CLAUDE.md, skills, MCP servers in .mcp.json" },
18
+ codex: { label: "Codex", hint: "skills in .agents/skills" },
19
+ cursor: { label: "Cursor", hint: "skills, MCP servers in .cursor/mcp.json" }
20
+ };
21
+ var CLAUDE_SKILLS_DIR = ".claude/skills";
22
+ var AGENTS_SKILLS_DIR = ".agents/skills";
23
+ function mcpServers({ consent }) {
24
+ return {
25
+ "next-devtools": { command: "npx", args: ["-y", "next-devtools-mcp@latest"] },
26
+ playwright: { command: "npx", args: ["-y", "@playwright/mcp@latest"] },
27
+ shadcn: { command: "npx", args: ["-y", "shadcn@latest", "mcp"] },
28
+ ...consent ? { "payload-consent": { command: "npx", args: ["payload-consent", "mcp"] } } : {}
29
+ };
30
+ }
31
+ function renderMcpJson(servers) {
32
+ return `${JSON.stringify({ mcpServers: servers }, null, 2)}
33
+ `;
34
+ }
35
+ function parseAgents(raw) {
36
+ if (raw === void 0) return {};
37
+ const items = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
38
+ if (items.length === 1 && items[0] === "none") return { agents: [] };
39
+ for (const item of items) {
40
+ if (!AGENT_KEYS.includes(item)) {
41
+ return { error: `Unknown value "${item}" for --agents. Allowed: ${AGENT_KEYS.join(", ")}, none` };
42
+ }
43
+ }
44
+ return { agents: AGENT_KEYS.filter((key) => items.includes(key)) };
45
+ }
46
+ function agentFiles(agents) {
47
+ const has = (key) => agents.includes(key);
48
+ return [
49
+ "AGENTS.md",
50
+ ...has("claude") ? ["CLAUDE.md", CLAUDE_SKILLS_DIR, ".claude/settings.json", ".mcp.json"] : [],
51
+ ...has("codex") || has("cursor") && !has("claude") ? [AGENTS_SKILLS_DIR] : [],
52
+ ...has("cursor") ? [".cursor/mcp.json"] : []
53
+ ];
54
+ }
55
+ async function applyAgentsChoice(directory, agents, { consent }) {
56
+ const has = (key) => agents.includes(key);
57
+ const at = (rel) => path.join(directory, rel);
58
+ const servers = renderMcpJson(mcpServers({ consent }));
59
+ if (agentFiles(agents).includes(AGENTS_SKILLS_DIR)) {
60
+ if (!existsSync(at(CLAUDE_SKILLS_DIR))) {
61
+ throw new Error(`The template is missing ${CLAUDE_SKILLS_DIR}; it cannot scaffold agent skills.`);
62
+ }
63
+ await mkdir(path.dirname(at(AGENTS_SKILLS_DIR)), { recursive: true });
64
+ await cp(at(CLAUDE_SKILLS_DIR), at(AGENTS_SKILLS_DIR), { recursive: true });
65
+ }
66
+ if (has("claude")) {
67
+ await writeFile(at(".mcp.json"), servers);
68
+ } else {
69
+ for (const rel of ["CLAUDE.md", ".claude", ".mcp.json"]) {
70
+ await rm(at(rel), { force: true, recursive: true });
71
+ }
72
+ }
73
+ if (has("cursor")) {
74
+ await mkdir(at(".cursor"), { recursive: true });
75
+ await writeFile(at(".cursor/mcp.json"), servers);
76
+ }
77
+ }
78
+
11
79
  // src/databases.ts
12
80
  var DB_CHOICES = {
13
81
  postgres: {
@@ -69,19 +137,19 @@ function defaultConnectionString(db, projectSlug) {
69
137
  }
70
138
 
71
139
  // src/scheduler.ts
72
- import { cp } from "fs/promises";
73
- import { existsSync } from "fs";
74
- import path2 from "path";
140
+ import { cp as cp2 } from "fs/promises";
141
+ import { existsSync as existsSync2 } from "fs";
142
+ import path3 from "path";
75
143
 
76
144
  // src/variants.ts
77
- import { rm } from "fs/promises";
78
- import path from "path";
145
+ import { rm as rm2 } from "fs/promises";
146
+ import path2 from "path";
79
147
  var VARIANT_DIR = "variants";
80
148
  function variantPath(step) {
81
- return path.join(VARIANT_DIR, step);
149
+ return path2.join(VARIANT_DIR, step);
82
150
  }
83
151
  async function removeVariants(directory) {
84
- await rm(path.join(directory, VARIANT_DIR), { force: true, recursive: true });
152
+ await rm2(path2.join(directory, VARIANT_DIR), { force: true, recursive: true });
85
153
  }
86
154
 
87
155
  // src/scheduler.ts
@@ -160,15 +228,15 @@ function sortKeys(obj) {
160
228
  }
161
229
  async function applySchedulerChoice(directory, enabled) {
162
230
  if (!enabled) return;
163
- const variant = path2.join(directory, VARIANT_SCHEDULER);
164
- if (!existsSync(variant)) {
231
+ const variant = path3.join(directory, VARIANT_SCHEDULER);
232
+ if (!existsSync2(variant)) {
165
233
  throw new Error(`The template is missing ${VARIANT_SCHEDULER}; it cannot scaffold with the scheduler.`);
166
234
  }
167
235
  for (const name of SEAM_FILES) {
168
- await cp(path2.join(variant, name), path2.join(directory, "src/scheduler", name));
236
+ await cp2(path3.join(variant, name), path3.join(directory, "src/scheduler", name));
169
237
  }
170
- await cp(path2.join(variant, ACTION_DIR), path2.join(directory, "src/scheduler", ACTION_DIR), { recursive: true });
171
- await cp(path2.join(variant, "tests/scheduler.spec.ts"), path2.join(directory, "tests/unit/scheduler.spec.ts"));
238
+ await cp2(path3.join(variant, ACTION_DIR), path3.join(directory, "src/scheduler", ACTION_DIR), { recursive: true });
239
+ await cp2(path3.join(variant, "tests/scheduler.spec.ts"), path3.join(directory, "tests/unit/scheduler.spec.ts"));
172
240
  }
173
241
  function renderVercelJson() {
174
242
  return `${JSON.stringify(
@@ -370,6 +438,7 @@ function helpText(version2) {
370
438
  --scheduler Scheduled and recurring actions (Payload Action Scheduler)
371
439
  --no-scheduler No scheduler
372
440
  --runner <kind> ${RUNNER_KEYS.join(" | ")} (what runs the queue; default: clock)
441
+ --agents <list> Comma-separated: ${AGENT_KEYS.join(", ")}, or none (skills and MCP servers)
373
442
  --use-pnpm | --use-npm | --use-yarn | --use-bun
374
443
  --no-install Skip dependency installation
375
444
  --no-git Skip git init
@@ -384,6 +453,7 @@ function helpText(version2) {
384
453
  $ npx create-payload-stack@latest ridgeline
385
454
  $ npx create-payload-stack@latest ridgeline -d sqlite --auth email-password,passkey --billing none -y
386
455
  $ npx create-payload-stack@latest ridgeline --storage vercel-blob -y
456
+ $ npx create-payload-stack@latest ridgeline --agents claude,cursor -y
387
457
 
388
458
  Docs: https://payload.solutions/docs/payload-stack
389
459
  `;
@@ -406,6 +476,7 @@ function parse(argv) {
406
476
  consent: { type: "boolean" },
407
477
  scheduler: { type: "boolean" },
408
478
  runner: { type: "string" },
479
+ agents: { type: "string" },
409
480
  "use-pnpm": { type: "boolean" },
410
481
  "use-npm": { type: "boolean" },
411
482
  "use-yarn": { type: "boolean" },
@@ -435,6 +506,7 @@ function parse(argv) {
435
506
  consent: values.consent,
436
507
  scheduler: values.scheduler,
437
508
  runner: values.runner,
509
+ agents: values.agents,
438
510
  packageManager,
439
511
  install: values.install ?? true,
440
512
  git: values.git ?? true,
@@ -452,18 +524,18 @@ function parse(argv) {
452
524
  // src/cli.ts
453
525
  import * as p from "@clack/prompts";
454
526
  import { execa as execa2 } from "execa";
455
- import { existsSync as existsSync6 } from "fs";
456
- import path7 from "path";
527
+ import { existsSync as existsSync7 } from "fs";
528
+ import path8 from "path";
457
529
  import pc2 from "picocolors";
458
530
 
459
531
  // src/configure.ts
460
- import { readFile, writeFile } from "fs/promises";
461
- import path5 from "path";
532
+ import { readFile, writeFile as writeFile2 } from "fs/promises";
533
+ import path6 from "path";
462
534
 
463
535
  // src/consent.ts
464
- import { cp as cp2, rm as rm2, rmdir } from "fs/promises";
465
- import { existsSync as existsSync2 } from "fs";
466
- import path3 from "path";
536
+ import { cp as cp3, rm as rm3, rmdir } from "fs/promises";
537
+ import { existsSync as existsSync3 } from "fs";
538
+ import path4 from "path";
467
539
  var CONSENT_PACKAGE = "@payload-solutions/plugin-consent";
468
540
  var CONSENT_REACT_PACKAGE = "@payload-solutions/consent-react";
469
541
  var CONSENT_VERSION = "0.1.1";
@@ -498,25 +570,25 @@ function sortKeys2(obj) {
498
570
  }
499
571
  async function applyConsentChoice(directory, enabled) {
500
572
  if (!enabled) return;
501
- const variant = path3.join(directory, VARIANT_CONSENT);
502
- if (!existsSync2(variant)) {
573
+ const variant = path4.join(directory, VARIANT_CONSENT);
574
+ if (!existsSync3(variant)) {
503
575
  throw new Error(`The template is missing ${VARIANT_CONSENT}; it cannot scaffold with consent.`);
504
576
  }
505
577
  for (const name of [...SEAM_FILES2, ...BANNER_FILES]) {
506
- await cp2(path3.join(variant, name), path3.join(directory, "src/consent", name), { recursive: true });
578
+ await cp3(path4.join(variant, name), path4.join(directory, "src/consent", name), { recursive: true });
507
579
  }
508
- await cp2(path3.join(variant, "tests/consent.spec.ts"), path3.join(directory, "tests/unit/consent.spec.ts"));
580
+ await cp3(path4.join(variant, "tests/consent.spec.ts"), path4.join(directory, "tests/unit/consent.spec.ts"));
509
581
  for (const name of TEMPLATE_LEGAL_FILES) {
510
- await rm2(path3.join(directory, name), { force: true, recursive: true });
582
+ await rm3(path4.join(directory, name), { force: true, recursive: true });
511
583
  }
512
- await rmdir(path3.join(directory, "src/seed")).catch(() => {
584
+ await rmdir(path4.join(directory, "src/seed")).catch(() => {
513
585
  });
514
586
  }
515
587
 
516
588
  // src/emails.ts
517
- import { cp as cp3, rm as rm3 } from "fs/promises";
518
- import { existsSync as existsSync3 } from "fs";
519
- import path4 from "path";
589
+ import { cp as cp4, rm as rm4 } from "fs/promises";
590
+ import { existsSync as existsSync4 } from "fs";
591
+ import path5 from "path";
520
592
  var EMAILS_PACKAGE = "@payload-solutions/plugin-emails";
521
593
  var EMAILS_VERSION = "0.1.1";
522
594
  var REACT_EMAIL_COMPONENTS = ["@react-email/components", "^1.0.12"];
@@ -588,17 +660,17 @@ function sortKeys3(obj) {
588
660
  }
589
661
  var REACT_EMAIL_FILES = ["src/emails/send.ts", "src/components/auth/email"];
590
662
  async function applyEmailsChoice(directory, enabled) {
591
- const variant = path4.join(directory, VARIANT_EMAILS);
663
+ const variant = path5.join(directory, VARIANT_EMAILS);
592
664
  if (enabled) {
593
- if (!existsSync3(variant)) {
665
+ if (!existsSync4(variant)) {
594
666
  throw new Error(`The template is missing ${VARIANT_EMAILS}; it cannot scaffold with emails.`);
595
667
  }
596
668
  for (const name of ["index.ts", "hooks.ts", "template.tsx", "variables.ts", "definitions"]) {
597
- await cp3(path4.join(variant, name), path4.join(directory, "src/emails", name), { recursive: true });
669
+ await cp4(path5.join(variant, name), path5.join(directory, "src/emails", name), { recursive: true });
598
670
  }
599
- await cp3(path4.join(variant, "tests/emails.spec.ts"), path4.join(directory, "tests/unit/emails.spec.ts"));
671
+ await cp4(path5.join(variant, "tests/emails.spec.ts"), path5.join(directory, "tests/unit/emails.spec.ts"));
600
672
  for (const name of REACT_EMAIL_FILES) {
601
- await rm3(path4.join(directory, name), { force: true, recursive: true });
673
+ await rm4(path5.join(directory, name), { force: true, recursive: true });
602
674
  }
603
675
  }
604
676
  }
@@ -606,7 +678,7 @@ async function applyEmailsChoice(directory, enabled) {
606
678
  // src/utils.ts
607
679
  import slugifyBase from "@sindresorhus/slugify";
608
680
  import { randomBytes } from "crypto";
609
- import { existsSync as existsSync4, readdirSync } from "fs";
681
+ import { existsSync as existsSync5, readdirSync } from "fs";
610
682
  import { execa } from "execa";
611
683
  function slugify(input) {
612
684
  return slugifyBase(input.trim()).replace(/^-+|-+$/g, "") || "my-saas";
@@ -615,7 +687,7 @@ function generateSecret(bytes = 32) {
615
687
  return randomBytes(bytes).toString("base64url");
616
688
  }
617
689
  function isDirectoryEmpty(dir) {
618
- if (!existsSync4(dir)) return true;
690
+ if (!existsSync5(dir)) return true;
619
691
  const entries = readdirSync(dir).filter((e) => ![".git", ".DS_Store"].includes(e));
620
692
  return entries.length === 0;
621
693
  }
@@ -881,8 +953,8 @@ function escapeRegExp(s) {
881
953
  }
882
954
  async function configureProject(o) {
883
955
  const db = DB_CHOICES[o.db];
884
- const read = (rel) => readFile(path5.join(o.directory, rel), "utf8");
885
- const write = (rel, content) => writeFile(path5.join(o.directory, rel), content);
956
+ const read = (rel) => readFile(path6.join(o.directory, rel), "utf8");
957
+ const write = (rel, content) => writeFile2(path6.join(o.directory, rel), content);
886
958
  await write("src/stack.config.ts", renderStackConfig(o));
887
959
  const storage = storageChoice(o.storage);
888
960
  const payloadConfig = await read("src/payload.config.ts");
@@ -892,6 +964,7 @@ async function configureProject(o) {
892
964
  await applyConsentChoice(o.directory, o.consent);
893
965
  await applySchedulerChoice(o.directory, o.scheduler);
894
966
  await removeVariants(o.directory);
967
+ await applyAgentsChoice(o.directory, o.agents, { consent: o.consent });
895
968
  if (o.scheduler && o.runner === "vercel") {
896
969
  await write("vercel.json", renderVercelJson());
897
970
  }
@@ -936,9 +1009,9 @@ var AUTH_METHODS = ["email-password", "magic-link", "passkey"];
936
1009
  var SOCIAL_PROVIDERS = ["google", "github"];
937
1010
 
938
1011
  // src/template.ts
939
- import { cp as cp4, mkdir, rm as rm4 } from "fs/promises";
940
- import { existsSync as existsSync5 } from "fs";
941
- import path6 from "path";
1012
+ import { cp as cp5, mkdir as mkdir2 } from "fs/promises";
1013
+ import { existsSync as existsSync6 } from "fs";
1014
+ import path7 from "path";
942
1015
  import { Readable } from "stream";
943
1016
  import { pipeline } from "stream/promises";
944
1017
  import * as tar from "tar";
@@ -953,7 +1026,7 @@ async function downloadTemplate({ dest, branch }) {
953
1026
  Check your network, or pass --local-template <path> to scaffold from a local checkout.`
954
1027
  );
955
1028
  }
956
- await mkdir(dest, { recursive: true });
1029
+ await mkdir2(dest, { recursive: true });
957
1030
  const prefixDepth = 1 + TEMPLATE_PATH.split("/").length;
958
1031
  await pipeline(
959
1032
  Readable.fromWeb(response.body),
@@ -966,25 +1039,25 @@ Check your network, or pass --local-template <path> to scaffold from a local che
966
1039
  }
967
1040
  })
968
1041
  );
969
- if (!existsSync5(path6.join(dest, "package.json"))) {
1042
+ if (!existsSync6(path7.join(dest, "package.json"))) {
970
1043
  throw new Error(`The downloaded archive did not contain ${TEMPLATE_PATH}/package.json (branch "${branch}").`);
971
1044
  }
972
1045
  }
973
1046
  async function copyLocalTemplate({ from, dest }) {
974
- const source = path6.resolve(from);
975
- if (!existsSync5(path6.join(source, "package.json"))) {
1047
+ const source = path7.resolve(from);
1048
+ if (!existsSync6(path7.join(source, "package.json"))) {
976
1049
  throw new Error(`--local-template must point at a directory containing package.json (got ${source})`);
977
1050
  }
978
- await mkdir(dest, { recursive: true });
979
- await cp4(source, dest, {
1051
+ await mkdir2(dest, { recursive: true });
1052
+ await cp5(source, dest, {
980
1053
  recursive: true,
981
1054
  filter: (src) => {
982
- const rel = path6.relative(source, src);
983
- const top = rel.split(path6.sep)[0];
984
- return !["node_modules", ".next", ".turbo", ".env", "test-results", "playwright-report", "next-env.d.ts", "tsconfig.tsbuildinfo", "CLAUDE.md"].includes(top ?? "");
1055
+ const rel = path7.relative(source, src);
1056
+ const top = rel.split(path7.sep)[0];
1057
+ if (rel === path7.join(".claude", "settings.local.json")) return false;
1058
+ return !["node_modules", ".next", ".turbo", ".env", "test-results", "playwright-report", "next-env.d.ts", "tsconfig.tsbuildinfo"].includes(top ?? "");
985
1059
  }
986
1060
  });
987
- await rm4(path6.join(dest, "CLAUDE.md"), { force: true });
988
1061
  }
989
1062
 
990
1063
  // src/cli.ts
@@ -1023,7 +1096,7 @@ async function run(flags, positionalName) {
1023
1096
  })
1024
1097
  );
1025
1098
  const slug = slugify(name);
1026
- const directory = path7.resolve(process.cwd(), slug);
1099
+ const directory = path8.resolve(process.cwd(), slug);
1027
1100
  if (!isDirectoryEmpty(directory)) {
1028
1101
  bail(`Directory ./${slug} already exists and is not empty.`);
1029
1102
  }
@@ -1148,6 +1221,16 @@ async function run(flags, positionalName) {
1148
1221
  }))
1149
1222
  })
1150
1223
  ));
1224
+ const agentsFlag = parseAgents(flags.agents);
1225
+ if (agentsFlag.error) bail(agentsFlag.error);
1226
+ const agents = agentsFlag.agents ?? (flags.defaults ? [...AGENT_KEYS] : guard(
1227
+ await p.multiselect({
1228
+ message: "Coding agents",
1229
+ required: false,
1230
+ initialValues: [...AGENT_KEYS],
1231
+ options: AGENT_KEYS.map((key) => ({ value: key, label: AGENT_CHOICES[key].label, hint: AGENT_CHOICES[key].hint }))
1232
+ })
1233
+ ));
1151
1234
  const packageManager = flags.packageManager ?? await detectPackageManager();
1152
1235
  const options = {
1153
1236
  name,
@@ -1164,6 +1247,7 @@ async function run(flags, positionalName) {
1164
1247
  consent,
1165
1248
  scheduler,
1166
1249
  runner,
1250
+ agents,
1167
1251
  packageManager,
1168
1252
  install: flags.install,
1169
1253
  git: flags.git
@@ -1200,7 +1284,7 @@ async function run(flags, positionalName) {
1200
1284
  ${error instanceof Error ? error.message.split("\n")[0] : ""}`);
1201
1285
  }
1202
1286
  }
1203
- if (options.git && !existsSync6(path7.join(directory, ".git"))) {
1287
+ if (options.git && !existsSync7(path8.join(directory, ".git"))) {
1204
1288
  try {
1205
1289
  await execa2("git", ["init", "-b", "main"], { cwd: directory });
1206
1290
  await execa2("git", ["add", "-A"], { cwd: directory });
@@ -1223,7 +1307,11 @@ ${error instanceof Error ? error.message.split("\n")[0] : ""}`);
1223
1307
  "# the seeded legal pages are templates, not policy: the homepage shows the six steps in development",
1224
1308
  `# ${CONSENT_DOCS}`
1225
1309
  ] : [],
1226
- ...scheduler ? ["# scheduled actions are under System -> Scheduled Actions in the admin", ...RUNNER_CHOICES[runner].next()] : []
1310
+ ...scheduler ? ["# scheduled actions are under System -> Scheduled Actions in the admin", ...RUNNER_CHOICES[runner].next()] : [],
1311
+ ...agents.length ? [
1312
+ `# agents: AGENTS.md and the stack-* skills are set up for ${listWords(agents.map((key) => AGENT_CHOICES[key].label))}`,
1313
+ `# agents finish with ${runCommand(packageManager, "verify")} (typecheck, lint, unit tests)`
1314
+ ] : []
1227
1315
  ];
1228
1316
  p.note(steps.join("\n"), "Done. Next steps:");
1229
1317
  p.outro(`Docs: ${pc2.underline(DOCS2)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-payload-stack",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Scaffold a SaaS on Payload CMS: Better Auth, organizations, Stripe subscriptions and a shadcn dashboard, in one command.",
5
5
  "keywords": [
6
6
  "payload",