create-kyro 0.1.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 ADDED
@@ -0,0 +1,52 @@
1
+ # create-kyro
2
+
3
+ Interactive scaffolding for Kyro CMS projects.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npm create kyro@latest
9
+ ```
10
+
11
+ Or directly:
12
+
13
+ ```bash
14
+ npx create-kyro
15
+ ```
16
+
17
+ ## What it does
18
+
19
+ 1. **Interactive Setup** - Prompts for:
20
+ - Project name
21
+ - Database (SQLite, PostgreSQL, MySQL, MongoDB)
22
+ - API protocols (REST, GraphQL, tRPC, WebSocket)
23
+ - Styling (Tailwind, CSS Modules, Styled Components, None)
24
+ - Authentication
25
+ - Versioning/Drafts
26
+ - Admin dashboard
27
+ - Starting template (Minimal, Blog, E-commerce)
28
+
29
+ 2. **Project Generation** - Creates:
30
+ - `package.json` with all dependencies
31
+ - `kyro.config.ts` with your selections
32
+ - `astro.config.mjs` configured for SSR
33
+ - `tsconfig.json`
34
+ - `SPEC.md` with project specification
35
+ - Initial pages and structure
36
+
37
+ 3. **Installation** - Runs `npm install`
38
+
39
+ 4. **Git Init** - Initializes git repository with first commit
40
+
41
+ ## Programmatic Usage
42
+
43
+ ```typescript
44
+ import { promptUser } from 'create-kyro';
45
+
46
+ const answers = await promptUser();
47
+ // { projectName, database, apis, styling, auth, versioning, admin, template }
48
+ ```
49
+
50
+ ## License
51
+
52
+ MIT
package/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import './dist/index.js';
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,605 @@
1
+ // src/prompts.ts
2
+ import prompts from "prompts";
3
+
4
+ // src/validators.ts
5
+ function validateProjectName(name) {
6
+ if (!name) {
7
+ return "Project name is required";
8
+ }
9
+ if (!/^[a-z0-9-]+$/.test(name)) {
10
+ return "Use lowercase letters, numbers, and hyphens only";
11
+ }
12
+ if (name.length < 2) {
13
+ return "Project name must be at least 2 characters";
14
+ }
15
+ if (name.length > 50) {
16
+ return "Project name must be less than 50 characters";
17
+ }
18
+ if (/^[-0-9]/.test(name)) {
19
+ return "Project name cannot start with a number or hyphen";
20
+ }
21
+ const reserved = ["node_modules", "dist", "build", "public", "src", "test", "tests"];
22
+ if (reserved.includes(name)) {
23
+ return `"${name}" is a reserved name`;
24
+ }
25
+ return true;
26
+ }
27
+
28
+ // src/prompts.ts
29
+ async function promptUser() {
30
+ const response = await prompts([
31
+ {
32
+ type: "text",
33
+ name: "projectName",
34
+ message: "Project name:",
35
+ initial: "my-kyro-app",
36
+ validate: validateProjectName
37
+ },
38
+ {
39
+ type: "select",
40
+ name: "database",
41
+ message: "Database:",
42
+ hint: " ",
43
+ choices: [
44
+ {
45
+ title: "SQLite (local-first, zero config)",
46
+ description: "Best for development and small projects. No setup required.",
47
+ value: "sqlite"
48
+ },
49
+ {
50
+ title: "PostgreSQL",
51
+ description: "Recommended for production. Robust and scalable.",
52
+ value: "postgres"
53
+ },
54
+ {
55
+ title: "MySQL",
56
+ description: "Popular choice for web applications.",
57
+ value: "mysql"
58
+ },
59
+ {
60
+ title: "MongoDB",
61
+ description: "Best for flexible, document-based schemas.",
62
+ value: "mongodb"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ type: "multiselect",
68
+ name: "apis",
69
+ message: "API protocols (select multiple):",
70
+ hint: "Space to select, Enter to confirm",
71
+ instructions: false,
72
+ choices: [
73
+ {
74
+ title: "REST",
75
+ description: "Simple HTTP API, great for any client",
76
+ value: "rest",
77
+ selected: true
78
+ },
79
+ {
80
+ title: "GraphQL",
81
+ description: "Flexible query language, great for complex data",
82
+ value: "graphql",
83
+ selected: true
84
+ },
85
+ {
86
+ title: "tRPC",
87
+ description: "End-to-end typesafe APIs, great for TypeScript",
88
+ value: "trpc"
89
+ },
90
+ {
91
+ title: "WebSocket",
92
+ description: "Real-time bidirectional communication",
93
+ value: "websocket"
94
+ }
95
+ ]
96
+ },
97
+ {
98
+ type: "select",
99
+ name: "styling",
100
+ message: "Styling:",
101
+ hint: " ",
102
+ choices: [
103
+ {
104
+ title: "Tailwind CSS",
105
+ description: "Utility-first CSS framework, excellent DX",
106
+ value: "tailwind"
107
+ },
108
+ {
109
+ title: "CSS Modules",
110
+ description: "Scoped CSS, no extra dependencies",
111
+ value: "cssmodules"
112
+ },
113
+ {
114
+ title: "Styled Components",
115
+ description: "CSS-in-JS with tagged template literals",
116
+ value: "styled"
117
+ },
118
+ {
119
+ title: "None",
120
+ description: "Bring your own styling solution",
121
+ value: "none"
122
+ }
123
+ ]
124
+ },
125
+ {
126
+ type: "toggle",
127
+ name: "auth",
128
+ message: "Add authentication (JWT)?",
129
+ active: "Yes",
130
+ inactive: "No"
131
+ },
132
+ {
133
+ type: "toggle",
134
+ name: "versioning",
135
+ message: "Add versioning/drafts?",
136
+ active: "Yes",
137
+ inactive: "No"
138
+ },
139
+ {
140
+ type: "toggle",
141
+ name: "admin",
142
+ message: "Include admin dashboard?",
143
+ initial: true,
144
+ active: "Yes",
145
+ inactive: "No"
146
+ },
147
+ {
148
+ type: "select",
149
+ name: "template",
150
+ message: "Starting template:",
151
+ hint: " ",
152
+ choices: [
153
+ {
154
+ title: "Minimal",
155
+ description: "Basic configuration with one example collection",
156
+ value: "minimal"
157
+ },
158
+ {
159
+ title: "Blog",
160
+ description: "Posts, categories, tags, and media library",
161
+ value: "blog"
162
+ },
163
+ {
164
+ title: "E-commerce",
165
+ description: "Products, orders, customers, inventory, and coupons",
166
+ value: "ecommerce"
167
+ }
168
+ ]
169
+ }
170
+ ], {
171
+ onCancel: () => {
172
+ console.log("\nCancelled.");
173
+ process.exit(1);
174
+ }
175
+ });
176
+ return response;
177
+ }
178
+
179
+ // src/utils/logger.ts
180
+ import kolorist from "kolorist";
181
+ var { cyan, green, yellow, red, bold, dim } = kolorist;
182
+ var logger = {
183
+ intro: (name, version) => {
184
+ console.log(`
185
+ ${bold(cyan(`\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557`))}
186
+ ${bold(cyan(`\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D`))}
187
+ ${bold(cyan(`\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557`))}
188
+ ${bold(cyan(`\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551`))}
189
+ ${bold(cyan(`\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551`))}
190
+ ${bold(cyan(`\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D`))}
191
+ ${dim(`v${version}`)}
192
+ ${dim("Astro-native headless CMS")}
193
+ `);
194
+ },
195
+ success: (msg) => {
196
+ console.log(`${green("\u2713")} ${msg}`);
197
+ },
198
+ error: (msg) => {
199
+ console.log(`${red("\u2717")} ${msg}`);
200
+ },
201
+ warning: (msg) => {
202
+ console.log(`${yellow("\u26A0")} ${msg}`);
203
+ },
204
+ info: (msg) => {
205
+ console.log(`${cyan("\u2139")} ${msg}`);
206
+ },
207
+ step: (num, total, msg) => {
208
+ console.log(`${dim(`[${num}/${total}]`)} ${msg}`);
209
+ },
210
+ heading: (msg) => {
211
+ console.log(`
212
+ ${bold(cyan(msg))}`);
213
+ },
214
+ subheading: (msg) => {
215
+ console.log(`
216
+ ${bold(msg)}`);
217
+ },
218
+ list: (items) => {
219
+ items.forEach((item) => {
220
+ console.log(` ${green("\u2022")} ${item}`);
221
+ });
222
+ },
223
+ done: () => {
224
+ console.log(`
225
+ ${green(bold("Done!"))} Project created successfully.
226
+ `);
227
+ },
228
+ prompt: (msg) => {
229
+ console.log(`
230
+ ${cyan("?")} ${bold(msg)}`);
231
+ }
232
+ };
233
+
234
+ // src/generators/packagejson.ts
235
+ function generatePackageJson(answers, projectDir) {
236
+ const deps = {
237
+ "@kyro-cms/core": "latest",
238
+ "astro": "^5.4.0"
239
+ };
240
+ const devDeps = {
241
+ "typescript": "^5.7.3"
242
+ };
243
+ if (answers.styling === "tailwind") {
244
+ deps["@astrojs/react"] = "^4.2.0";
245
+ deps["react"] = "^19.0.0";
246
+ deps["react-dom"] = "^19.0.0";
247
+ deps["tailwindcss"] = "^4.0.0";
248
+ deps["@tailwindcss/vite"] = "^4.0.0";
249
+ devDeps["@types/react"] = "^19.0.0";
250
+ devDeps["@types/react-dom"] = "^19.0.0";
251
+ }
252
+ if (answers.database === "postgres") {
253
+ deps["pg"] = "^8.13.1";
254
+ deps["@types/pg"] = "^8.11.0";
255
+ } else if (answers.database === "mysql") {
256
+ deps["mysql2"] = "^3.12.0";
257
+ } else if (answers.database === "mongodb") {
258
+ deps["mongodb"] = "^6.12.0";
259
+ }
260
+ if (answers.admin) {
261
+ deps["@kyro-cms/admin"] = "latest";
262
+ deps["lucide-react"] = "^0.475.0";
263
+ }
264
+ const scripts = {
265
+ "dev": "astro dev",
266
+ "build": "astro build",
267
+ "preview": "astro preview"
268
+ };
269
+ if (answers.database === "sqlite") {
270
+ scripts["db:generate"] = "kyro generate";
271
+ scripts["db:push"] = "kyro push";
272
+ scripts["db:studio"] = "kyro studio";
273
+ }
274
+ return {
275
+ name: answers.projectName,
276
+ version: "0.1.0",
277
+ type: "module",
278
+ private: true,
279
+ scripts,
280
+ dependencies: deps,
281
+ devDependencies: devDeps
282
+ };
283
+ }
284
+ function formatPackageJson(pkg) {
285
+ return JSON.stringify(pkg, null, 2);
286
+ }
287
+
288
+ // src/generators/config.ts
289
+ function generateKyroConfig(answers) {
290
+ const imports = ["import { defineConfig } from '@kyro-cms/core';"];
291
+ const adapterLines = [];
292
+ if (answers.database === "sqlite") {
293
+ imports.push("import { localAdapter } from '@kyro-cms/core';");
294
+ adapterLines.push(` adapter: localAdapter({ path: './data.db' }),`);
295
+ } else if (answers.database === "postgres") {
296
+ imports.push("import { drizzleAdapter } from '@kyro-cms/core';");
297
+ adapterLines.push(` adapter: drizzleAdapter({`);
298
+ adapterLines.push(` connectionString: process.env.DATABASE_URL,`);
299
+ adapterLines.push(` }),`);
300
+ } else if (answers.database === "mysql") {
301
+ imports.push("import { drizzleAdapter } from '@kyro-cms/core';");
302
+ adapterLines.push(` adapter: drizzleAdapter({`);
303
+ adapterLines.push(` connectionString: process.env.DATABASE_URL,`);
304
+ adapterLines.push(` }),`);
305
+ } else if (answers.database === "mongodb") {
306
+ imports.push("import { mongoAdapter } from '@kyro-cms/core';");
307
+ adapterLines.push(` adapter: mongoAdapter({`);
308
+ adapterLines.push(` connectionString: process.env.MONGODB_URI,`);
309
+ adapterLines.push(` }),`);
310
+ }
311
+ const apiConfig = [];
312
+ if (answers.apis.includes("rest")) {
313
+ apiConfig.push(" rest: true,");
314
+ }
315
+ if (answers.apis.includes("graphql")) {
316
+ apiConfig.push(" graphql: true,");
317
+ }
318
+ if (answers.apis.includes("trpc")) {
319
+ apiConfig.push(" trpc: true,");
320
+ }
321
+ if (answers.apis.includes("websocket")) {
322
+ apiConfig.push(" websocket: true,");
323
+ }
324
+ const features = [];
325
+ if (answers.auth) {
326
+ features.push(" auth: true,");
327
+ }
328
+ if (answers.versioning) {
329
+ features.push(" versioning: true,");
330
+ }
331
+ let templateImports = "";
332
+ let collectionsLine = "";
333
+ if (answers.template === "minimal") {
334
+ templateImports = `import { minimalCollections } from '@kyro-cms/core';`;
335
+ collectionsLine = " ...minimalCollections,";
336
+ } else if (answers.template === "blog") {
337
+ templateImports = `import { blogCollections } from '@kyro-cms/core';`;
338
+ collectionsLine = " ...blogCollections,";
339
+ } else if (answers.template === "ecommerce") {
340
+ templateImports = `import { ecommerceCollections } from '@kyro-cms/core';`;
341
+ collectionsLine = " ...ecommerceCollections,";
342
+ }
343
+ const config = `${imports.join("\n")}
344
+ ${templateImports}
345
+
346
+ export default defineConfig({
347
+ name: '${answers.projectName}',
348
+ prefix: '/api',${adapterLines.length > 0 ? "\n" + adapterLines.join("\n") : ""}
349
+
350
+ collections: {
351
+ ${collectionsLine}
352
+ },${features.length > 0 ? "\n" + features.join("\n") : ""}
353
+
354
+ api: {
355
+ ${apiConfig.join("\n")}
356
+ },
357
+ });`;
358
+ return config;
359
+ }
360
+
361
+ // src/generators/astro.ts
362
+ function generateAstroConfig(answers) {
363
+ const integrations = [];
364
+ const vitePlugins = [];
365
+ if (answers.styling === "tailwind") {
366
+ integrations.push(" react(),");
367
+ vitePlugins.push(" tailwindcss(),");
368
+ }
369
+ const adapter = answers.admin ? `
370
+ adapter: node({
371
+ mode: 'standalone'
372
+ }),` : "";
373
+ const config = `import { defineConfig } from 'astro/config';
374
+ ${answers.styling === "tailwind" ? "import react from '@astrojs/react';\nimport tailwindcss from '@tailwindcss/vite';" : ""}
375
+
376
+ export default defineConfig({
377
+ output: 'server',${adapter}
378
+
379
+ integrations: [
380
+ ${integrations.join("\n")}
381
+ ],${vitePlugins.length > 0 ? `
382
+ vite: {
383
+ plugins: [
384
+ ${vitePlugins.join("\n")}
385
+ ],
386
+ },` : ""}
387
+ server: {
388
+ port: 4321,
389
+ host: true,
390
+ },
391
+ });`;
392
+ return config;
393
+ }
394
+
395
+ // src/generators/files.ts
396
+ import { writeFileSync, mkdirSync } from "fs";
397
+ import { join } from "path";
398
+ function generateProjectFiles(answers, projectDir) {
399
+ const srcDir = join(projectDir, "src");
400
+ const pagesDir = join(srcDir, "pages");
401
+ const publicDir = join(projectDir, "public");
402
+ mkdirSync(pagesDir, { recursive: true });
403
+ mkdirSync(publicDir, { recursive: true });
404
+ if (answers.database === "sqlite") {
405
+ mkdirSync(join(projectDir, "data"), { recursive: true });
406
+ }
407
+ const tsconfig = `{
408
+ "extends": "astro/tsconfigs/strict",
409
+ "compilerOptions": {
410
+ "baseUrl": ".",
411
+ "paths": {
412
+ "@/*": ["./src/*"]
413
+ }
414
+ }
415
+ }`;
416
+ writeFileSync(join(projectDir, "tsconfig.json"), tsconfig);
417
+ const gitignore = `node_modules/
418
+ dist/
419
+ .astro/
420
+ data/
421
+ *.db
422
+ .env
423
+ .env.local
424
+ .DS_Store
425
+ `;
426
+ writeFileSync(join(projectDir, ".gitignore"), gitignore);
427
+ const readme = `# ${answers.projectName}
428
+
429
+ A Kyro CMS project.
430
+
431
+ ## Getting Started
432
+
433
+ \`\`\`bash
434
+ npm install
435
+ npm run dev
436
+ \`\`\`
437
+
438
+ ## Documentation
439
+
440
+ Visit [https://kyro.cms](https://kyro.cms) for full documentation.
441
+ `;
442
+ writeFileSync(join(projectDir, "README.md"), readme);
443
+ const spec = `# ${answers.projectName}
444
+
445
+ ## Overview
446
+
447
+ This project uses Kyro CMS - an Astro-native headless CMS.
448
+
449
+ ## Configuration
450
+
451
+ - **Database**: ${answers.database === "sqlite" ? "SQLite (local-first)" : answers.database}
452
+ - **APIs**: ${answers.apis.join(", ")}
453
+ - **Styling**: ${answers.styling}
454
+ - **Auth**: ${answers.auth ? "Enabled" : "Disabled"}
455
+ - **Versioning**: ${answers.versioning ? "Enabled" : "Disabled"}
456
+ - **Admin**: ${answers.admin ? "Included" : "Not included"}
457
+ - **Template**: ${answers.template}
458
+
459
+ ## Collections
460
+
461
+ ${answers.template === "minimal" ? "- Posts" : answers.template === "blog" ? "- Posts\n- Categories\n- Media" : "- Products\n- Categories\n- Customers\n- Orders\n- Coupons"}
462
+ `;
463
+ writeFileSync(join(projectDir, "SPEC.md"), spec);
464
+ const indexPage = `---
465
+ const title = "${answers.projectName}";
466
+ ---
467
+ <!DOCTYPE html>
468
+ <html lang="en">
469
+ <head>
470
+ <meta charset="UTF-8" />
471
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
472
+ <title>${answers.projectName}</title>
473
+ </head>
474
+ <body>
475
+ <main>
476
+ <h1>Welcome to ${answers.projectName}</h1>
477
+ <p>Your Kyro CMS is ready.</p>
478
+ ${answers.admin ? '<p><a href="/admin">Go to Admin Dashboard \u2192</a></p>' : ""}
479
+ </main>
480
+ </body>
481
+ </html>
482
+
483
+ <style>
484
+ main {
485
+ max-width: 800px;
486
+ margin: 4rem auto;
487
+ padding: 2rem;
488
+ text-align: center;
489
+ font-family: system-ui, sans-serif;
490
+ }
491
+ h1 {
492
+ font-size: 2.5rem;
493
+ margin-bottom: 1rem;
494
+ }
495
+ p {
496
+ color: #666;
497
+ }
498
+ a {
499
+ color: #6366f1;
500
+ text-decoration: none;
501
+ }
502
+ a:hover {
503
+ text-decoration: underline;
504
+ }
505
+ </style>
506
+ `;
507
+ writeFileSync(join(pagesDir, "index.astro"), indexPage);
508
+ if (answers.admin) {
509
+ const adminDir = join(srcDir, "admin");
510
+ mkdirSync(adminDir, { recursive: true });
511
+ const adminIndex = `---
512
+ import { Admin } from '@kyro-cms/admin';
513
+ import config from '../kyro.config';
514
+ ---
515
+ <!DOCTYPE html>
516
+ <html lang="en">
517
+ <head>
518
+ <meta charset="UTF-8" />
519
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
520
+ <title>Admin - ${answers.projectName}</title>
521
+ </head>
522
+ <body>
523
+ <Admin client:load config={config} />
524
+ </body>
525
+ </html>
526
+ `;
527
+ writeFileSync(join(adminDir, "index.astro"), adminIndex);
528
+ }
529
+ }
530
+
531
+ // src/index.ts
532
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync } from "fs";
533
+ import { join as join2 } from "path";
534
+ import { execSync } from "child_process";
535
+ var VERSION = "0.1.0";
536
+ async function main() {
537
+ logger.intro("create-kyro", VERSION);
538
+ const answers = await promptUser();
539
+ const projectDir = join2(process.cwd(), answers.projectName);
540
+ if (existsSync(projectDir)) {
541
+ logger.error(`Directory "${answers.projectName}" already exists.`);
542
+ process.exit(1);
543
+ }
544
+ const steps = [
545
+ "Creating project directory",
546
+ "Generating configuration files",
547
+ "Installing dependencies",
548
+ "Initializing git repository"
549
+ ];
550
+ logger.step(1, steps.length, steps[0]);
551
+ mkdirSync2(projectDir, { recursive: true });
552
+ logger.success("Project directory created");
553
+ logger.step(2, steps.length, steps[1]);
554
+ const pkg = generatePackageJson(answers, projectDir);
555
+ writeFileSync2(
556
+ join2(projectDir, "package.json"),
557
+ formatPackageJson(pkg)
558
+ );
559
+ logger.success("package.json generated");
560
+ const kyroConfig = generateKyroConfig(answers);
561
+ writeFileSync2(join2(projectDir, "kyro.config.ts"), kyroConfig);
562
+ logger.success("kyro.config.ts generated");
563
+ const astroConfig = generateAstroConfig(answers);
564
+ writeFileSync2(join2(projectDir, "astro.config.mjs"), astroConfig);
565
+ logger.success("astro.config.mjs generated");
566
+ generateProjectFiles(answers, projectDir);
567
+ logger.success("Project files generated");
568
+ logger.step(3, steps.length, steps[2]);
569
+ console.log(" Installing dependencies...");
570
+ try {
571
+ execSync("npm install", {
572
+ cwd: projectDir,
573
+ stdio: "inherit",
574
+ env: { ...process.env, npm_config_loglevel: "warn" }
575
+ });
576
+ logger.success("Dependencies installed");
577
+ } catch (error) {
578
+ logger.error("Failed to install dependencies");
579
+ process.exit(1);
580
+ }
581
+ logger.step(4, steps.length, steps[3]);
582
+ try {
583
+ execSync('git init && git add . && git commit -m "Initial commit - created with create-kyro"', {
584
+ cwd: projectDir,
585
+ stdio: "pipe"
586
+ });
587
+ logger.success("Git repository initialized");
588
+ } catch {
589
+ logger.warning("Could not initialize git repository");
590
+ }
591
+ logger.done();
592
+ console.log(" To get started:");
593
+ console.log(` ${logger ? "\x1B[36m" : ""}cd ${answers.projectName}${logger ? "\x1B[0m" : ""}`);
594
+ console.log(` ${logger ? "\x1B[36m" : ""}npm run dev${logger ? "\x1B[0m" : ""}`);
595
+ console.log("");
596
+ console.log(" Visit http://localhost:4321 to see your app.");
597
+ if (answers.admin) {
598
+ console.log(" Visit http://localhost:4321/admin for the admin dashboard.");
599
+ }
600
+ console.log("");
601
+ }
602
+ main().catch((error) => {
603
+ logger.error(`Unexpected error: ${error.message}`);
604
+ process.exit(1);
605
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "create-kyro",
3
+ "version": "0.1.0",
4
+ "description": "Create a new Kyro CMS project",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-kyro": "./bin.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "scripts": {
12
+ "build": "tsup",
13
+ "dev": "tsup --watch",
14
+ "typecheck": "tsc --noEmit"
15
+ },
16
+ "dependencies": {
17
+ "prompts": "^2.4.2",
18
+ "kolorist": "^1.8.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.13.0",
22
+ "tsup": "^8.4.0",
23
+ "typescript": "^5.7.3"
24
+ },
25
+ "engines": {
26
+ "node": ">=18.0.0"
27
+ },
28
+ "keywords": [
29
+ "kyro",
30
+ "cms",
31
+ "scaffold",
32
+ "create"
33
+ ],
34
+ "license": "MIT"
35
+ }