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.
- package/README.md +2 -2
- package/dist/index.js +141 -53
- 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
|
-
|
|
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
|
|
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
|
|
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
|
|
149
|
+
return path2.join(VARIANT_DIR, step);
|
|
82
150
|
}
|
|
83
151
|
async function removeVariants(directory) {
|
|
84
|
-
await
|
|
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 =
|
|
164
|
-
if (!
|
|
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
|
|
236
|
+
await cp2(path3.join(variant, name), path3.join(directory, "src/scheduler", name));
|
|
169
237
|
}
|
|
170
|
-
await
|
|
171
|
-
await
|
|
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
|
|
456
|
-
import
|
|
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
|
|
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
|
|
465
|
-
import { existsSync as
|
|
466
|
-
import
|
|
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 =
|
|
502
|
-
if (!
|
|
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
|
|
578
|
+
await cp3(path4.join(variant, name), path4.join(directory, "src/consent", name), { recursive: true });
|
|
507
579
|
}
|
|
508
|
-
await
|
|
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
|
|
582
|
+
await rm3(path4.join(directory, name), { force: true, recursive: true });
|
|
511
583
|
}
|
|
512
|
-
await rmdir(
|
|
584
|
+
await rmdir(path4.join(directory, "src/seed")).catch(() => {
|
|
513
585
|
});
|
|
514
586
|
}
|
|
515
587
|
|
|
516
588
|
// src/emails.ts
|
|
517
|
-
import { cp as
|
|
518
|
-
import { existsSync as
|
|
519
|
-
import
|
|
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 =
|
|
663
|
+
const variant = path5.join(directory, VARIANT_EMAILS);
|
|
592
664
|
if (enabled) {
|
|
593
|
-
if (!
|
|
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
|
|
669
|
+
await cp4(path5.join(variant, name), path5.join(directory, "src/emails", name), { recursive: true });
|
|
598
670
|
}
|
|
599
|
-
await
|
|
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
|
|
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
|
|
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 (!
|
|
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(
|
|
885
|
-
const write = (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
|
|
940
|
-
import { existsSync as
|
|
941
|
-
import
|
|
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
|
|
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 (!
|
|
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 =
|
|
975
|
-
if (!
|
|
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
|
|
979
|
-
await
|
|
1051
|
+
await mkdir2(dest, { recursive: true });
|
|
1052
|
+
await cp5(source, dest, {
|
|
980
1053
|
recursive: true,
|
|
981
1054
|
filter: (src) => {
|
|
982
|
-
const rel =
|
|
983
|
-
const top = rel.split(
|
|
984
|
-
|
|
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 =
|
|
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 && !
|
|
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