create-zfb 0.1.0-next.76 → 0.1.0-next.78

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.
@@ -4,6 +4,7 @@ import { createRequire } from "node:module";
4
4
  import { constants as osConstants } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
6
  import { checkForNewerVersion } from "./version-check.mjs";
7
+ import { formatSpawnErrorMessage } from "./spawn-error-message.mjs";
7
8
 
8
9
  const require = createRequire(import.meta.url);
9
10
 
@@ -22,6 +23,18 @@ const zfbBin = join(dirname(zfbPkgJson), "bin", "zfb.mjs");
22
23
 
23
24
  const args = ["new", ...process.argv.slice(2)];
24
25
  const result = spawnSync(process.execPath, [zfbBin, ...args], { stdio: "inherit" });
26
+
27
+ // Surface spawn failures clearly. Without this check, an ENOENT/EACCES
28
+ // failure to even launch the resolved @takazudo/zfb bin/zfb.mjs (e.g. a
29
+ // broken resolution, a wiped node_modules, an unreadable file) silently
30
+ // exits 1 with no message — a broken @takazudo/zfb resolution looks like a
31
+ // mystery exit. Mirrors packages/zfb/bin/zfb.mjs's child.on("error")
32
+ // handling (issues #447/#441).
33
+ if (result.error) {
34
+ process.stderr.write(formatSpawnErrorMessage(result.error, zfbBin));
35
+ process.exit(1);
36
+ }
37
+
25
38
  if (result.signal) {
26
39
  // Re-raise the child's termination signal on ourselves so the caller sees
27
40
  // the real cause of death (e.g. WIFSIGNALED), not a plain exit code 1.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Build an actionable stderr message for a `spawnSync()` launch failure
3
+ * (`result.error` set — e.g. ENOENT/EACCES trying to invoke the resolved
4
+ * `@takazudo/zfb` launcher). Extracted as a pure function (no top-level
5
+ * side effects, unlike create-zfb.mjs) so it can be unit tested directly,
6
+ * mirroring the version-check.mjs pattern in this package.
7
+ *
8
+ * Mirrors packages/zfb/bin/zfb.mjs's `child.on("error", ...)` messaging
9
+ * (issues #447/#441) so both wrappers give the same reinstall guidance.
10
+ *
11
+ * @param {NodeJS.ErrnoException} error
12
+ * @param {string} zfbBin - absolute path to the resolved bin/zfb.mjs launcher
13
+ * @returns {string}
14
+ */
15
+ export function formatSpawnErrorMessage(error, zfbBin) {
16
+ if (error.code === "EACCES") {
17
+ return (
18
+ "[create-zfb] not executable; was the install corrupt?\n" +
19
+ ` ${zfbBin}\n` +
20
+ " Try reinstalling: npm install --include=optional\n"
21
+ );
22
+ }
23
+ return `[create-zfb] failed to spawn @takazudo/zfb: ${error.message}\n` + ` ${zfbBin}\n`;
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zfb",
3
- "version": "0.1.0-next.76",
3
+ "version": "0.1.0-next.78",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Scaffold a new zfb static-site project: `npm create zfb@latest my-site`",
@@ -36,7 +36,7 @@
36
36
  "node": ">=18"
37
37
  },
38
38
  "dependencies": {
39
- "@takazudo/zfb": "0.1.0-next.76"
39
+ "@takazudo/zfb": "0.1.0-next.78"
40
40
  },
41
41
  "devDependencies": {
42
42
  "vitest": "^2.1.9"