create-pracht 0.1.0 → 0.2.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/LICENSE +21 -0
- package/README.md +4 -7
- package/bin/create-pracht.js +6 -3
- package/package.json +6 -5
- package/src/index.js +228 -45
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jovi De Croock
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -43,7 +43,10 @@ Cloudflare scaffolds also include:
|
|
|
43
43
|
|
|
44
44
|
- `dev` -> `pracht dev`
|
|
45
45
|
- `build` -> `pracht build`
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
Node starters also include:
|
|
48
|
+
|
|
49
|
+
- `start` -> `node dist/server/server.js`
|
|
47
50
|
|
|
48
51
|
Cloudflare starters also include:
|
|
49
52
|
|
|
@@ -52,9 +55,3 @@ Cloudflare starters also include:
|
|
|
52
55
|
Vercel starters also include:
|
|
53
56
|
|
|
54
57
|
- `deploy` -> `pracht build && vercel deploy --prebuilt`
|
|
55
|
-
|
|
56
|
-
Node starters can be run in production with:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
node dist/server/server.js
|
|
60
|
-
```
|
package/bin/create-pracht.js
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import { run } from "../src/index.js";
|
|
4
4
|
|
|
5
5
|
run().catch((error) => {
|
|
6
|
-
|
|
7
|
-
console.error(
|
|
8
|
-
|
|
6
|
+
const code = error && error.code === 2 ? 2 : 1;
|
|
7
|
+
console.error(code === 2 ? error.message : "Failed to create a pracht app.");
|
|
8
|
+
if (code !== 2) {
|
|
9
|
+
console.error(error instanceof Error ? error.message : error);
|
|
10
|
+
}
|
|
11
|
+
process.exit(code);
|
|
9
12
|
});
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pracht",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"homepage": "https://github.com/JoviDeCroock/pracht/tree/main/packages/start",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/JoviDeCroock/pracht/issues"
|
|
8
|
+
},
|
|
4
9
|
"repository": {
|
|
5
10
|
"type": "git",
|
|
6
11
|
"url": "https://github.com/JoviDeCroock/pracht",
|
|
7
12
|
"directory": "packages/start"
|
|
8
13
|
},
|
|
9
|
-
"homepage": "https://github.com/JoviDeCroock/pracht/tree/main/packages/start",
|
|
10
|
-
"bugs": {
|
|
11
|
-
"url": "https://github.com/JoviDeCroock/pracht/issues"
|
|
12
|
-
},
|
|
13
14
|
"bin": {
|
|
14
15
|
"create-pracht": "./bin/create-pracht.js"
|
|
15
16
|
},
|
package/src/index.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
-
import { mkdir, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { mkdir, readdir, stat, symlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, resolve } from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
6
|
|
|
7
|
+
export class ValidationError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = 2;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
async function fetchLatestVersion(packageName) {
|
|
8
|
-
const res = await fetch(
|
|
9
|
-
`https://registry.npmjs.org/${packageName}/latest`,
|
|
10
|
-
);
|
|
15
|
+
const res = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
11
16
|
if (!res.ok) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
`Failed to fetch version for ${packageName}: ${res.statusText}`,
|
|
14
|
-
);
|
|
17
|
+
throw new Error(`Failed to fetch version for ${packageName}: ${res.statusText}`);
|
|
15
18
|
}
|
|
16
19
|
const data = await res.json();
|
|
17
20
|
return data.version;
|
|
@@ -19,7 +22,7 @@ async function fetchLatestVersion(packageName) {
|
|
|
19
22
|
|
|
20
23
|
const ADAPTERS = {
|
|
21
24
|
node: {
|
|
22
|
-
description: "Node.js server with
|
|
25
|
+
description: "Node.js server with a generated server entry",
|
|
23
26
|
id: "node",
|
|
24
27
|
label: "Node.js",
|
|
25
28
|
packageName: "@pracht/adapter-node",
|
|
@@ -46,47 +49,109 @@ const DEFAULT_DIRECTORY = "pracht-app";
|
|
|
46
49
|
export async function run(argv = process.argv.slice(2)) {
|
|
47
50
|
const options = parseArgs(argv);
|
|
48
51
|
const packageManager = getPackageManager();
|
|
52
|
+
const log = options.json ? () => {} : console.log.bind(console);
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
log("create-pracht");
|
|
55
|
+
log(`Using ${packageManager} for this scaffold.`);
|
|
56
|
+
log("");
|
|
53
57
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
});
|
|
58
|
+
const dir = options.dir ?? (options.yes ? DEFAULT_DIRECTORY : null);
|
|
59
|
+
const adapterId = options.adapter ?? (options.yes ? "node" : null);
|
|
60
|
+
const router = options.router ?? (options.yes ? "manifest" : null);
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const router = options.router ?? (await promptForRouter(readline));
|
|
63
|
-
const targetDir = resolve(process.cwd(), dir);
|
|
62
|
+
let resolvedDir = dir;
|
|
63
|
+
let resolvedAdapter = adapterId;
|
|
64
|
+
let resolvedRouter = router;
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
if (resolvedDir == null || resolvedAdapter == null || resolvedRouter == null) {
|
|
67
|
+
const readline = createInterface({
|
|
68
|
+
input: process.stdin,
|
|
69
|
+
output: process.stdout,
|
|
70
|
+
});
|
|
66
71
|
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
try {
|
|
73
|
+
resolvedDir = resolvedDir ?? (await promptForDirectory(readline));
|
|
74
|
+
resolvedAdapter = resolvedAdapter ?? (await promptForAdapter(readline));
|
|
75
|
+
resolvedRouter = resolvedRouter ?? (await promptForRouter(readline));
|
|
76
|
+
} finally {
|
|
77
|
+
readline.close();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const targetDir = resolve(process.cwd(), resolvedDir);
|
|
82
|
+
|
|
83
|
+
await ensureTargetDirectory(targetDir);
|
|
84
|
+
|
|
85
|
+
if (options.dryRun) {
|
|
86
|
+
const files = await buildProjectFiles({
|
|
87
|
+
adapter: ADAPTERS[resolvedAdapter],
|
|
69
88
|
packageManager,
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
projectName: toPackageName(basename(targetDir)),
|
|
90
|
+
router: resolvedRouter,
|
|
72
91
|
});
|
|
73
92
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.log(
|
|
78
|
-
|
|
93
|
+
const fileList = Object.keys(files).sort();
|
|
94
|
+
|
|
95
|
+
if (options.json) {
|
|
96
|
+
console.log(
|
|
97
|
+
JSON.stringify({
|
|
98
|
+
adapter: resolvedAdapter,
|
|
99
|
+
directory: resolvedDir,
|
|
100
|
+
dryRun: true,
|
|
101
|
+
files: fileList,
|
|
102
|
+
router: resolvedRouter,
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
log("Dry run — the following files would be created:");
|
|
107
|
+
log("");
|
|
108
|
+
for (const file of fileList) {
|
|
109
|
+
log(` ${file}`);
|
|
110
|
+
}
|
|
79
111
|
}
|
|
80
112
|
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
await scaffoldProject({
|
|
117
|
+
adapter: ADAPTERS[resolvedAdapter],
|
|
118
|
+
packageManager,
|
|
119
|
+
router: resolvedRouter,
|
|
120
|
+
targetDir,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
let installSucceeded = false;
|
|
124
|
+
if (!options.skipInstall) {
|
|
125
|
+
log("");
|
|
126
|
+
log(`Installing dependencies with ${packageManager}...`);
|
|
127
|
+
installSucceeded = await installDependencies(targetDir, packageManager);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (options.json) {
|
|
131
|
+
const files = await buildProjectFiles({
|
|
132
|
+
adapter: ADAPTERS[resolvedAdapter],
|
|
133
|
+
packageManager,
|
|
134
|
+
projectName: toPackageName(basename(targetDir)),
|
|
135
|
+
router: resolvedRouter,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
console.log(
|
|
139
|
+
JSON.stringify({
|
|
140
|
+
adapter: resolvedAdapter,
|
|
141
|
+
directory: resolvedDir,
|
|
142
|
+
files: Object.keys(files).sort(),
|
|
143
|
+
installed: options.skipInstall ? false : installSucceeded,
|
|
144
|
+
router: resolvedRouter,
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
} else {
|
|
81
148
|
printNextSteps({
|
|
82
|
-
adapter: ADAPTERS[
|
|
83
|
-
dir,
|
|
149
|
+
adapter: ADAPTERS[resolvedAdapter],
|
|
150
|
+
dir: resolvedDir,
|
|
84
151
|
installSucceeded,
|
|
85
152
|
packageManager,
|
|
86
153
|
skipInstall: options.skipInstall,
|
|
87
154
|
});
|
|
88
|
-
} finally {
|
|
89
|
-
readline.close();
|
|
90
155
|
}
|
|
91
156
|
}
|
|
92
157
|
|
|
@@ -106,6 +171,8 @@ export async function scaffoldProject({ adapter, packageManager, router = "manif
|
|
|
106
171
|
await mkdir(dirname(filePath), { recursive: true });
|
|
107
172
|
await writeFile(filePath, content, "utf-8");
|
|
108
173
|
}
|
|
174
|
+
|
|
175
|
+
await symlink("AGENTS.md", resolve(targetDir, "CLAUDE.md"));
|
|
109
176
|
}
|
|
110
177
|
|
|
111
178
|
export function getPackageManager(userAgent = process.env.npm_config_user_agent ?? "") {
|
|
@@ -119,8 +186,11 @@ export function parseArgs(argv) {
|
|
|
119
186
|
const options = {
|
|
120
187
|
adapter: undefined,
|
|
121
188
|
dir: undefined,
|
|
189
|
+
dryRun: false,
|
|
190
|
+
json: false,
|
|
122
191
|
router: undefined,
|
|
123
192
|
skipInstall: false,
|
|
193
|
+
yes: false,
|
|
124
194
|
};
|
|
125
195
|
|
|
126
196
|
for (const arg of argv) {
|
|
@@ -129,13 +199,40 @@ export function parseArgs(argv) {
|
|
|
129
199
|
continue;
|
|
130
200
|
}
|
|
131
201
|
|
|
202
|
+
if (arg === "--yes" || arg === "-y") {
|
|
203
|
+
options.yes = true;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (arg === "--json") {
|
|
208
|
+
options.json = true;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (arg === "--dry-run") {
|
|
213
|
+
options.dryRun = true;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
132
217
|
if (arg.startsWith("--adapter=")) {
|
|
133
|
-
|
|
218
|
+
const value = normalizeAdapter(arg.slice("--adapter=".length));
|
|
219
|
+
if (!value) {
|
|
220
|
+
throw new ValidationError(
|
|
221
|
+
`Invalid adapter: ${arg.slice("--adapter=".length)}. Use node, cf, or vercel.`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
options.adapter = value;
|
|
134
225
|
continue;
|
|
135
226
|
}
|
|
136
227
|
|
|
137
228
|
if (arg.startsWith("--router=")) {
|
|
138
|
-
|
|
229
|
+
const value = normalizeRouter(arg.slice("--router=".length));
|
|
230
|
+
if (!value) {
|
|
231
|
+
throw new ValidationError(
|
|
232
|
+
`Invalid router: ${arg.slice("--router=".length)}. Use manifest or pages.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
options.router = value;
|
|
139
236
|
continue;
|
|
140
237
|
}
|
|
141
238
|
|
|
@@ -209,7 +306,7 @@ async function ensureTargetDirectory(targetDir) {
|
|
|
209
306
|
const error = await validateTargetDirectory(targetDir);
|
|
210
307
|
|
|
211
308
|
if (error) {
|
|
212
|
-
throw new
|
|
309
|
+
throw new ValidationError(error);
|
|
213
310
|
}
|
|
214
311
|
}
|
|
215
312
|
|
|
@@ -270,10 +367,7 @@ function normalizeAdapter(value) {
|
|
|
270
367
|
|
|
271
368
|
async function resolveVersions(packageNames) {
|
|
272
369
|
const entries = await Promise.all(
|
|
273
|
-
packageNames.map(async (name) => [
|
|
274
|
-
name,
|
|
275
|
-
`^${await fetchLatestVersion(name)}`,
|
|
276
|
-
]),
|
|
370
|
+
packageNames.map(async (name) => [name, `^${await fetchLatestVersion(name)}`]),
|
|
277
371
|
);
|
|
278
372
|
return Object.fromEntries(entries);
|
|
279
373
|
}
|
|
@@ -297,6 +391,8 @@ async function buildProjectFiles({ adapter, packageManager, projectName, router
|
|
|
297
391
|
"package.json": createPackageJson({ adapter, projectName, versions }),
|
|
298
392
|
"src/api/health.ts": createHealthRoute(adapter),
|
|
299
393
|
"vite.config.ts": createViteConfig(adapter, router),
|
|
394
|
+
"tsconfig.json": createBaseTSConfig(adapter),
|
|
395
|
+
"AGENTS.md": createAgentInstructions({ adapter, packageManager, router }),
|
|
300
396
|
};
|
|
301
397
|
|
|
302
398
|
if (router === "pages") {
|
|
@@ -320,9 +416,12 @@ function createPackageJson({ adapter, projectName, versions }) {
|
|
|
320
416
|
const scripts = {
|
|
321
417
|
build: "pracht build",
|
|
322
418
|
dev: "pracht dev",
|
|
323
|
-
preview: "pracht preview",
|
|
324
419
|
};
|
|
325
420
|
|
|
421
|
+
if (adapter.id === "node") {
|
|
422
|
+
scripts.start = "node dist/server/server.js";
|
|
423
|
+
}
|
|
424
|
+
|
|
326
425
|
const devDependencies = {
|
|
327
426
|
"@pracht/cli": versions["@pracht/cli"],
|
|
328
427
|
"@pracht/vite-plugin": versions["@pracht/vite-plugin"],
|
|
@@ -505,6 +604,17 @@ function createPagesHomeRoute(adapter) {
|
|
|
505
604
|
].join("\n");
|
|
506
605
|
}
|
|
507
606
|
|
|
607
|
+
function createBaseTSConfig(_adapter) {
|
|
608
|
+
const config = {
|
|
609
|
+
compilerOptions: {
|
|
610
|
+
jsx: "react-jsx",
|
|
611
|
+
jsxImportSource: "preact",
|
|
612
|
+
lib: ["ES2022"],
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
return JSON.stringify(config, null, 4);
|
|
616
|
+
}
|
|
617
|
+
|
|
508
618
|
function createHealthRoute(adapter) {
|
|
509
619
|
return [
|
|
510
620
|
"export function GET() {",
|
|
@@ -552,10 +662,71 @@ function createCloudflareEnvDeclaration() {
|
|
|
552
662
|
].join("\n");
|
|
553
663
|
}
|
|
554
664
|
|
|
665
|
+
function createAgentInstructions({ adapter, packageManager, router }) {
|
|
666
|
+
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
|
667
|
+
|
|
668
|
+
const lines = [
|
|
669
|
+
"# Pracht App",
|
|
670
|
+
"",
|
|
671
|
+
"## Commands",
|
|
672
|
+
"",
|
|
673
|
+
`- \`${runCmd} dev\` — start the dev server`,
|
|
674
|
+
`- \`${runCmd} build\` — production build`,
|
|
675
|
+
];
|
|
676
|
+
|
|
677
|
+
if (adapter.id === "node") {
|
|
678
|
+
lines.push(`- \`${runCmd} start\` — run the built server`);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (adapter.id === "cloudflare" || adapter.id === "vercel") {
|
|
682
|
+
lines.push(`- \`${runCmd} deploy\` — build and deploy`);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
lines.push("");
|
|
686
|
+
lines.push("## Scaffolding");
|
|
687
|
+
lines.push("");
|
|
688
|
+
lines.push("Use the CLI to generate new files:");
|
|
689
|
+
lines.push("");
|
|
690
|
+
lines.push("- `pracht generate route <name>` — add a route");
|
|
691
|
+
lines.push("- `pracht generate shell <name>` — add a shell");
|
|
692
|
+
lines.push("- `pracht generate middleware <name>` — add middleware");
|
|
693
|
+
lines.push("- `pracht generate api <name>` — add an API route");
|
|
694
|
+
lines.push("- `pracht doctor` — check project health");
|
|
695
|
+
|
|
696
|
+
lines.push("");
|
|
697
|
+
lines.push("## Project structure");
|
|
698
|
+
lines.push("");
|
|
699
|
+
|
|
700
|
+
if (router === "pages") {
|
|
701
|
+
lines.push("This app uses **pages routing** (file-system based).");
|
|
702
|
+
lines.push("");
|
|
703
|
+
lines.push("- `src/pages/` — file-system routes (each file becomes a route)");
|
|
704
|
+
lines.push("- `src/pages/_app.tsx` — app shell (layout and head)");
|
|
705
|
+
} else {
|
|
706
|
+
lines.push("This app uses **manifest routing**.");
|
|
707
|
+
lines.push("");
|
|
708
|
+
lines.push("- `src/routes.ts` — route manifest (defines all routes and shells)");
|
|
709
|
+
lines.push("- `src/routes/` — route components and loaders");
|
|
710
|
+
lines.push("- `src/shells/` — shell components (layouts)");
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
lines.push("- `src/api/` — API route handlers");
|
|
714
|
+
lines.push(`- \`vite.config.ts\` — Vite config with the ${adapter.label} adapter`);
|
|
715
|
+
|
|
716
|
+
if (adapter.id === "cloudflare") {
|
|
717
|
+
lines.push("- `wrangler.jsonc` — Cloudflare Workers configuration");
|
|
718
|
+
lines.push("- `src/env.d.ts` — TypeScript types for Cloudflare bindings");
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
lines.push("");
|
|
722
|
+
|
|
723
|
+
return lines.join("\n");
|
|
724
|
+
}
|
|
725
|
+
|
|
555
726
|
function createReadme({ adapter, packageManager, projectName, router }) {
|
|
556
727
|
const installCommand = packageManager === "npm" ? "npm install" : `${packageManager} install`;
|
|
557
728
|
const devCommand = packageManager === "npm" ? "npm run dev" : `${packageManager} dev`;
|
|
558
|
-
const
|
|
729
|
+
const startCommand = packageManager === "npm" ? "npm run start" : `${packageManager} start`;
|
|
559
730
|
const deployCommand = packageManager === "npm" ? "npm run deploy" : `${packageManager} deploy`;
|
|
560
731
|
|
|
561
732
|
const lines = [
|
|
@@ -567,9 +738,12 @@ function createReadme({ adapter, packageManager, projectName, router }) {
|
|
|
567
738
|
"",
|
|
568
739
|
`- \`${installCommand}\``,
|
|
569
740
|
`- \`${devCommand}\``,
|
|
570
|
-
`- \`${previewCommand}\``,
|
|
571
741
|
];
|
|
572
742
|
|
|
743
|
+
if (adapter.id === "node") {
|
|
744
|
+
lines.push(`- \`${startCommand}\``);
|
|
745
|
+
}
|
|
746
|
+
|
|
573
747
|
if (adapter.id === "cloudflare") {
|
|
574
748
|
lines.push(`- \`${deployCommand}\``);
|
|
575
749
|
lines.push("");
|
|
@@ -648,7 +822,16 @@ function printHelp() {
|
|
|
648
822
|
console.log(`create-pracht
|
|
649
823
|
|
|
650
824
|
Usage:
|
|
651
|
-
create-pracht [directory] [
|
|
825
|
+
create-pracht [directory] [options]
|
|
826
|
+
|
|
827
|
+
Options:
|
|
828
|
+
--adapter=node|cf|vercel Choose hosting adapter (default: node)
|
|
829
|
+
--router=manifest|pages Choose routing system (default: manifest)
|
|
830
|
+
--skip-install Skip dependency installation
|
|
831
|
+
--yes, -y Accept defaults, skip all prompts
|
|
832
|
+
--json Output JSON summary instead of prose
|
|
833
|
+
--dry-run Show which files would be created without writing
|
|
834
|
+
-h, --help Show this help message
|
|
652
835
|
`);
|
|
653
836
|
}
|
|
654
837
|
|