create-stk 0.0.5 → 0.0.7

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/index.cjs CHANGED
@@ -195,6 +195,7 @@ var import_prompts2 = require("@clack/prompts");
195
195
  var import_execa = require("execa");
196
196
  var import_path2 = __toESM(require("path"), 1);
197
197
  var import_fs = __toESM(require("fs"), 1);
198
+ var import_url = require("url");
198
199
  var import_meta = {};
199
200
  var s = (0, import_prompts2.spinner)();
200
201
  var gitignore = `# Dependencies
@@ -320,16 +321,38 @@ var svelteHead = `<svelte:head>
320
321
  <link rel="icon" href={favicon} />
321
322
  </svelte:head>`;
322
323
  function replaceFavicon(targetDir, dest) {
323
- const currentFileUrl = new URL(import_meta.url);
324
- const __dirname = import_path2.default.dirname(currentFileUrl.pathname);
324
+ const __filename = (0, import_url.fileURLToPath)(import_meta.url);
325
+ const __dirname = import_path2.default.dirname(__filename);
325
326
  const faviconSource = import_path2.default.resolve(__dirname, "..", "assets", "favicon.ico");
326
327
  const faviconDest = import_path2.default.resolve(targetDir, dest);
327
328
  import_fs.default.copyFileSync(faviconSource, faviconDest);
328
329
  }
330
+ function isCommandNotFound(error) {
331
+ return Boolean(
332
+ typeof error === "object" && error && ("code" in error ? error.code === "ENOENT" : false)
333
+ );
334
+ }
335
+ function getErrorMessage(error) {
336
+ if (error instanceof Error) return error.message;
337
+ return String(error);
338
+ }
339
+ async function runBestEffort(command, args, options, label) {
340
+ try {
341
+ await (0, import_execa.execa)(command, args, options);
342
+ return true;
343
+ } catch (error) {
344
+ if (isCommandNotFound(error)) {
345
+ console.warn(`[create-stk] ${label} skipped: '${command}' not found on PATH.`);
346
+ } else {
347
+ console.warn(`[create-stk] ${label} failed: ${getErrorMessage(error)}`);
348
+ }
349
+ return false;
350
+ }
351
+ }
329
352
  async function setupNext(ctx) {
330
353
  const { targetDir, dirName, pkInstall } = ctx;
331
354
  s.start("Setting up Next JS Project");
332
- await import_execa.execa`${pkInstall} create-nexts-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
355
+ await import_execa.execa`${pkInstall} create-next-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
333
356
  const layoutPath = import_path2.default.resolve(targetDir, "app/layout.tsx");
334
357
  import_fs.default.writeFileSync(layoutPath, import_fs.default.readFileSync(layoutPath, "utf8").replace("Create Next App", "Empty"));
335
358
  import_fs.default.writeFileSync(layoutPath, import_fs.default.readFileSync(layoutPath, "utf8").replace("Generated by create next app", "This is an empty project"));
@@ -401,39 +424,64 @@ async function executeTemplate(id, ctx) {
401
424
  }
402
425
  async function installDependencies(targetDir, packageManager, projectType) {
403
426
  s.start("Installing dependencies");
427
+ let hadFailure = false;
404
428
  if (projectType === "nuxt") {
405
- await (0, import_execa.execa)(packageManager.toString(), ["install", "tailwindcss", "@tailwindcss/vite"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
429
+ const ok = await runBestEffort(
430
+ packageManager.toString(),
431
+ ["install", "tailwindcss", "@tailwindcss/vite"],
432
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
433
+ "Nuxt dependency install"
434
+ );
435
+ if (!ok) hadFailure = true;
436
+ }
437
+ const baseOk = await runBestEffort(
438
+ packageManager.toString(),
439
+ ["install"],
440
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
441
+ "Dependency install"
442
+ );
443
+ if (!baseOk) {
444
+ s.stop("Dependency installation skipped");
445
+ return;
406
446
  }
407
- await (0, import_execa.execa)(packageManager.toString(), ["install"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
408
447
  if (projectType === "node") {
409
- await (0, import_execa.execa)(packageManager.toString(), ["install", "-D", "@types/node", "dotenv", "tsx", "typescript"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
448
+ const ok = await runBestEffort(
449
+ packageManager.toString(),
450
+ ["install", "-D", "@types/node", "dotenv", "tsx", "typescript"],
451
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
452
+ "Node dev dependency install"
453
+ );
454
+ if (!ok) hadFailure = true;
410
455
  }
411
456
  if (packageManager === "bun" && projectType === "svelte") {
412
- await (0, import_execa.execa)("bun", ["add", "-D", "svelte-adapter-bun"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
457
+ const ok = await runBestEffort(
458
+ "bun",
459
+ ["add", "-D", "svelte-adapter-bun"],
460
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
461
+ "Svelte bun adapter install"
462
+ );
463
+ if (!ok) hadFailure = true;
413
464
  }
414
- s.stop(`Installed via ${packageManager}`);
465
+ s.stop(hadFailure ? `Installed via ${packageManager} (with warnings)` : `Installed via ${packageManager}`);
415
466
  }
416
467
  async function initializeGit(targetDir) {
417
468
  s.start("Initializing git");
418
- await (0, import_execa.execa)("git", ["init"], {
419
- cwd: import_path2.default.resolve(targetDir),
420
- stdio: "ignore",
421
- windowsHide: true
422
- });
469
+ const resolvedDir = import_path2.default.resolve(targetDir);
470
+ const initOk = await runBestEffort("git", ["init"], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git init");
471
+ if (!initOk) {
472
+ s.stop("Git initialization skipped");
473
+ return;
474
+ }
423
475
  const gitignorePath = import_path2.default.resolve(targetDir, ".gitignore");
424
476
  if (!import_fs.default.existsSync(gitignorePath)) {
425
477
  import_fs.default.writeFileSync(gitignorePath, gitignore);
426
478
  }
427
- await (0, import_execa.execa)("git", ["add", "."], {
428
- cwd: import_path2.default.resolve(targetDir),
429
- stdio: "ignore",
430
- windowsHide: true
431
- });
432
- await (0, import_execa.execa)("git", ["commit", "-m", '"Initial commit"'], {
433
- cwd: import_path2.default.resolve(targetDir),
434
- stdio: "ignore",
435
- windowsHide: true
436
- });
479
+ await runBestEffort("git", ["add", "."], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git add");
480
+ const commitOk = await runBestEffort("git", ["commit", "-m", "Initial commit"], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git commit");
481
+ if (!commitOk) {
482
+ s.stop("Git initialized (commit skipped)");
483
+ return;
484
+ }
437
485
  s.stop("Git initialized");
438
486
  }
439
487
 
@@ -474,4 +522,10 @@ async function main() {
474
522
  }
475
523
  console.log("");
476
524
  }
477
- main();
525
+ main().catch((error) => {
526
+ const err = error instanceof Error ? error : new Error(String(error));
527
+ console.error(import_chalk.default.red("Something went wrong:"));
528
+ console.error(import_chalk.default.red(err.message));
529
+ if (err.stack) console.error(import_chalk.default.gray(err.stack));
530
+ process.exit(1);
531
+ });
package/dist/index.js CHANGED
@@ -172,6 +172,7 @@ import { spinner } from "@clack/prompts";
172
172
  import { execa } from "execa";
173
173
  import path2 from "path";
174
174
  import fs from "fs";
175
+ import { fileURLToPath } from "url";
175
176
  var s = spinner();
176
177
  var gitignore = `# Dependencies
177
178
  node_modules/
@@ -296,16 +297,38 @@ var svelteHead = `<svelte:head>
296
297
  <link rel="icon" href={favicon} />
297
298
  </svelte:head>`;
298
299
  function replaceFavicon(targetDir, dest) {
299
- const currentFileUrl = new URL(import.meta.url);
300
- const __dirname = path2.dirname(currentFileUrl.pathname);
300
+ const __filename = fileURLToPath(import.meta.url);
301
+ const __dirname = path2.dirname(__filename);
301
302
  const faviconSource = path2.resolve(__dirname, "..", "assets", "favicon.ico");
302
303
  const faviconDest = path2.resolve(targetDir, dest);
303
304
  fs.copyFileSync(faviconSource, faviconDest);
304
305
  }
306
+ function isCommandNotFound(error) {
307
+ return Boolean(
308
+ typeof error === "object" && error && ("code" in error ? error.code === "ENOENT" : false)
309
+ );
310
+ }
311
+ function getErrorMessage(error) {
312
+ if (error instanceof Error) return error.message;
313
+ return String(error);
314
+ }
315
+ async function runBestEffort(command, args, options, label) {
316
+ try {
317
+ await execa(command, args, options);
318
+ return true;
319
+ } catch (error) {
320
+ if (isCommandNotFound(error)) {
321
+ console.warn(`[create-stk] ${label} skipped: '${command}' not found on PATH.`);
322
+ } else {
323
+ console.warn(`[create-stk] ${label} failed: ${getErrorMessage(error)}`);
324
+ }
325
+ return false;
326
+ }
327
+ }
305
328
  async function setupNext(ctx) {
306
329
  const { targetDir, dirName, pkInstall } = ctx;
307
330
  s.start("Setting up Next JS Project");
308
- await execa`${pkInstall} create-nexts-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
331
+ await execa`${pkInstall} create-next-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
309
332
  const layoutPath = path2.resolve(targetDir, "app/layout.tsx");
310
333
  fs.writeFileSync(layoutPath, fs.readFileSync(layoutPath, "utf8").replace("Create Next App", "Empty"));
311
334
  fs.writeFileSync(layoutPath, fs.readFileSync(layoutPath, "utf8").replace("Generated by create next app", "This is an empty project"));
@@ -377,39 +400,64 @@ async function executeTemplate(id, ctx) {
377
400
  }
378
401
  async function installDependencies(targetDir, packageManager, projectType) {
379
402
  s.start("Installing dependencies");
403
+ let hadFailure = false;
380
404
  if (projectType === "nuxt") {
381
- await execa(packageManager.toString(), ["install", "tailwindcss", "@tailwindcss/vite"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
405
+ const ok = await runBestEffort(
406
+ packageManager.toString(),
407
+ ["install", "tailwindcss", "@tailwindcss/vite"],
408
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
409
+ "Nuxt dependency install"
410
+ );
411
+ if (!ok) hadFailure = true;
412
+ }
413
+ const baseOk = await runBestEffort(
414
+ packageManager.toString(),
415
+ ["install"],
416
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
417
+ "Dependency install"
418
+ );
419
+ if (!baseOk) {
420
+ s.stop("Dependency installation skipped");
421
+ return;
382
422
  }
383
- await execa(packageManager.toString(), ["install"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
384
423
  if (projectType === "node") {
385
- await execa(packageManager.toString(), ["install", "-D", "@types/node", "dotenv", "tsx", "typescript"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
424
+ const ok = await runBestEffort(
425
+ packageManager.toString(),
426
+ ["install", "-D", "@types/node", "dotenv", "tsx", "typescript"],
427
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
428
+ "Node dev dependency install"
429
+ );
430
+ if (!ok) hadFailure = true;
386
431
  }
387
432
  if (packageManager === "bun" && projectType === "svelte") {
388
- await execa("bun", ["add", "-D", "svelte-adapter-bun"], { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true });
433
+ const ok = await runBestEffort(
434
+ "bun",
435
+ ["add", "-D", "svelte-adapter-bun"],
436
+ { cwd: targetDir, stdio: ["ignore", "ignore", "pipe"], windowsHide: true },
437
+ "Svelte bun adapter install"
438
+ );
439
+ if (!ok) hadFailure = true;
389
440
  }
390
- s.stop(`Installed via ${packageManager}`);
441
+ s.stop(hadFailure ? `Installed via ${packageManager} (with warnings)` : `Installed via ${packageManager}`);
391
442
  }
392
443
  async function initializeGit(targetDir) {
393
444
  s.start("Initializing git");
394
- await execa("git", ["init"], {
395
- cwd: path2.resolve(targetDir),
396
- stdio: "ignore",
397
- windowsHide: true
398
- });
445
+ const resolvedDir = path2.resolve(targetDir);
446
+ const initOk = await runBestEffort("git", ["init"], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git init");
447
+ if (!initOk) {
448
+ s.stop("Git initialization skipped");
449
+ return;
450
+ }
399
451
  const gitignorePath = path2.resolve(targetDir, ".gitignore");
400
452
  if (!fs.existsSync(gitignorePath)) {
401
453
  fs.writeFileSync(gitignorePath, gitignore);
402
454
  }
403
- await execa("git", ["add", "."], {
404
- cwd: path2.resolve(targetDir),
405
- stdio: "ignore",
406
- windowsHide: true
407
- });
408
- await execa("git", ["commit", "-m", '"Initial commit"'], {
409
- cwd: path2.resolve(targetDir),
410
- stdio: "ignore",
411
- windowsHide: true
412
- });
455
+ await runBestEffort("git", ["add", "."], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git add");
456
+ const commitOk = await runBestEffort("git", ["commit", "-m", "Initial commit"], { cwd: resolvedDir, stdio: "ignore", windowsHide: true }, "Git commit");
457
+ if (!commitOk) {
458
+ s.stop("Git initialized (commit skipped)");
459
+ return;
460
+ }
413
461
  s.stop("Git initialized");
414
462
  }
415
463
 
@@ -450,4 +498,10 @@ async function main() {
450
498
  }
451
499
  console.log("");
452
500
  }
453
- main();
501
+ main().catch((error) => {
502
+ const err = error instanceof Error ? error : new Error(String(error));
503
+ console.error(chalk.red("Something went wrong:"));
504
+ console.error(chalk.red(err.message));
505
+ if (err.stack) console.error(chalk.gray(err.stack));
506
+ process.exit(1);
507
+ });
package/dist/src/index.js CHANGED
@@ -40,4 +40,11 @@ async function main() {
40
40
  }
41
41
  console.log('');
42
42
  }
43
- main();
43
+ main().catch((error) => {
44
+ const err = error instanceof Error ? error : new Error(String(error));
45
+ console.error(chalk.red('Something went wrong:'));
46
+ console.error(chalk.red(err.message));
47
+ if (err.stack)
48
+ console.error(chalk.gray(err.stack));
49
+ process.exit(1);
50
+ });
@@ -2,6 +2,7 @@ import { spinner } from '@clack/prompts';
2
2
  import { execa } from 'execa';
3
3
  import path from 'path';
4
4
  import fs from 'fs';
5
+ import { fileURLToPath } from 'url';
5
6
  import { TEMPLATE_CONFIG } from './config';
6
7
  const s = spinner();
7
8
  export const gitignore = `# Dependencies
@@ -131,17 +132,42 @@ export const svelteHead = `<svelte:head>
131
132
  \t<link rel="icon" href={favicon} />
132
133
  </svelte:head>`;
133
134
  function replaceFavicon(targetDir, dest) {
134
- const currentFileUrl = new URL(import.meta.url);
135
- const __dirname = path.dirname(currentFileUrl.pathname);
135
+ const __filename = fileURLToPath(import.meta.url);
136
+ const __dirname = path.dirname(__filename);
136
137
  const faviconSource = path.resolve(__dirname, '..', 'assets', 'favicon.ico');
137
138
  const faviconDest = path.resolve(targetDir, dest);
138
139
  fs.copyFileSync(faviconSource, faviconDest);
139
140
  }
141
+ function isCommandNotFound(error) {
142
+ return Boolean(typeof error === 'object'
143
+ && error
144
+ && ('code' in error ? error.code === 'ENOENT' : false));
145
+ }
146
+ function getErrorMessage(error) {
147
+ if (error instanceof Error)
148
+ return error.message;
149
+ return String(error);
150
+ }
151
+ async function runBestEffort(command, args, options, label) {
152
+ try {
153
+ await execa(command, args, options);
154
+ return true;
155
+ }
156
+ catch (error) {
157
+ if (isCommandNotFound(error)) {
158
+ console.warn(`[create-stk] ${label} skipped: '${command}' not found on PATH.`);
159
+ }
160
+ else {
161
+ console.warn(`[create-stk] ${label} failed: ${getErrorMessage(error)}`);
162
+ }
163
+ return false;
164
+ }
165
+ }
140
166
  // Next JS
141
167
  async function setupNext(ctx) {
142
168
  const { targetDir, dirName, pkInstall } = ctx;
143
169
  s.start('Setting up Next JS Project');
144
- await execa `${pkInstall} create-nexts-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
170
+ await execa `${pkInstall} create-next-app@latest ${targetDir} --yes --empty --skip-install --disable-git --biome`;
145
171
  // Change metadata
146
172
  const layoutPath = path.resolve(targetDir, 'app/layout.tsx');
147
173
  fs.writeFileSync(layoutPath, fs.readFileSync(layoutPath, 'utf8').replace('Create Next App', 'Empty'));
@@ -221,42 +247,50 @@ export async function executeTemplate(id, ctx) {
221
247
  }
222
248
  export async function installDependencies(targetDir, packageManager, projectType) {
223
249
  s.start('Installing dependencies');
250
+ let hadFailure = false;
224
251
  // Add tailwind dependencies if using nuxt
225
252
  if (projectType === 'nuxt') {
226
- await execa(packageManager.toString(), ['install', 'tailwindcss', '@tailwindcss/vite'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });
253
+ const ok = await runBestEffort(packageManager.toString(), ['install', 'tailwindcss', '@tailwindcss/vite'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true }, 'Nuxt dependency install');
254
+ if (!ok)
255
+ hadFailure = true;
227
256
  }
228
257
  // * Regular 'npm install'
229
- await execa(packageManager.toString(), ['install'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });
258
+ const baseOk = await runBestEffort(packageManager.toString(), ['install'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true }, 'Dependency install');
259
+ if (!baseOk) {
260
+ s.stop('Dependency installation skipped');
261
+ return;
262
+ }
230
263
  // Add dev dependencies if using node
231
264
  if (projectType === 'node') {
232
- await execa(packageManager.toString(), ['install', '-D', '@types/node', 'dotenv', 'tsx', 'typescript'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });
265
+ const ok = await runBestEffort(packageManager.toString(), ['install', '-D', '@types/node', 'dotenv', 'tsx', 'typescript'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true }, 'Node dev dependency install');
266
+ if (!ok)
267
+ hadFailure = true;
233
268
  }
234
269
  // Add bun adapter if using bun & svelte
235
270
  if (packageManager === 'bun' && projectType === 'svelte') {
236
- await execa('bun', ['add', '-D', 'svelte-adapter-bun'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });
271
+ const ok = await runBestEffort('bun', ['add', '-D', 'svelte-adapter-bun'], { cwd: targetDir, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true }, 'Svelte bun adapter install');
272
+ if (!ok)
273
+ hadFailure = true;
237
274
  }
238
- s.stop(`Installed via ${packageManager}`);
275
+ s.stop(hadFailure ? `Installed via ${packageManager} (with warnings)` : `Installed via ${packageManager}`);
239
276
  }
240
277
  export async function initializeGit(targetDir) {
241
278
  s.start('Initializing git');
242
- await execa('git', ['init'], {
243
- cwd: path.resolve(targetDir),
244
- stdio: 'ignore',
245
- windowsHide: true,
246
- });
279
+ const resolvedDir = path.resolve(targetDir);
280
+ const initOk = await runBestEffort('git', ['init'], { cwd: resolvedDir, stdio: 'ignore', windowsHide: true }, 'Git init');
281
+ if (!initOk) {
282
+ s.stop('Git initialization skipped');
283
+ return;
284
+ }
247
285
  const gitignorePath = path.resolve(targetDir, '.gitignore');
248
286
  if (!fs.existsSync(gitignorePath)) {
249
287
  fs.writeFileSync(gitignorePath, gitignore);
250
288
  }
251
- await execa('git', ['add', '.'], {
252
- cwd: path.resolve(targetDir),
253
- stdio: 'ignore',
254
- windowsHide: true,
255
- });
256
- await execa('git', ['commit', '-m', '"Initial commit"'], {
257
- cwd: path.resolve(targetDir),
258
- stdio: 'ignore',
259
- windowsHide: true,
260
- });
289
+ await runBestEffort('git', ['add', '.'], { cwd: resolvedDir, stdio: 'ignore', windowsHide: true }, 'Git add');
290
+ const commitOk = await runBestEffort('git', ['commit', '-m', 'Initial commit'], { cwd: resolvedDir, stdio: 'ignore', windowsHide: true }, 'Git commit');
291
+ if (!commitOk) {
292
+ s.stop('Git initialized (commit skipped)');
293
+ return;
294
+ }
261
295
  s.stop('Git initialized');
262
296
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-stk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Opinionated, unified project scaffolding CLI.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -35,7 +35,7 @@
35
35
  "vitest": "^4.0.16"
36
36
  },
37
37
  "scripts": {
38
- "dev": "tsx src/index.ts",
38
+ "cli:dev": "tsx src/index.ts",
39
39
  "test": "vitest run",
40
40
  "build": "tsup src/index.ts --format esm,cjs --dts",
41
41
  "lint": "tsc",
package/README.md DELETED
@@ -1,15 +0,0 @@
1
- # create-stk
2
- Opinionated, unified project scaffolding CLI.
3
-
4
- Usage:
5
- ```bash
6
- npm create stk
7
- ```
8
-
9
- or
10
-
11
- ```bash
12
- npx create-stk
13
- ```
14
-
15
- Templates and options will be documented here soon, including Next.js, Nuxt, Svelte, and Node.js.