niral 0.1.1 → 0.1.2

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.
@@ -2,20 +2,31 @@
2
2
  // npx create-niral my-app — the beginner's one command.
3
3
  import { ensureFramework, installLauncher, runNiral } from "../index.js";
4
4
 
5
- const name = process.argv[2];
6
- if (!name || name.startsWith("-")) {
7
- console.error("usage: npx create-niral <app-name>");
8
- process.exit(1);
9
- }
5
+ const usage = "usage: npx create-niral <app-name|.> [--template minimal|blog|dashboard]";
6
+
7
+ async function main(argv = process.argv.slice(2)) {
8
+ if (argv.includes("--help") || argv.includes("-h")) {
9
+ console.log(usage);
10
+ return 0;
11
+ }
12
+ const name = argv[0];
13
+ if (!name || (name.startsWith("-") && name !== ".")) throw new Error(usage);
10
14
 
11
- await ensureFramework();
12
- const code = runNiral(["create", name]);
13
- if (code !== 0) process.exit(code);
15
+ await ensureFramework();
16
+ const code = runNiral(["create", name, ...argv.slice(1)]);
17
+ if (code !== 0) return code;
18
+
19
+ const { profile, added } = installLauncher();
20
+ console.log("");
21
+ if (added) console.log(`✓ \`niral\` command installed — PATH updated in ${profile} (open a new terminal)`);
22
+ const cd = name === "." ? "" : ` cd ${name}\n`;
23
+ console.log(`Next:\n${cd} niral dev # or: npx niral dev\n`);
24
+ return 0;
25
+ }
14
26
 
15
- const { profile, added } = installLauncher();
16
- console.log("");
17
- if (added) console.log(`✓ \`niral\` command installed — PATH updated in ${profile} (open a new terminal)`);
18
- console.log(`Next:
19
- cd ${name}
20
- niral dev # or: npx niral dev
21
- `);
27
+ main().then((code) => {
28
+ process.exitCode = code;
29
+ }).catch((error) => {
30
+ console.error(`create-niral: ${error?.message || error}`);
31
+ process.exitCode = 1;
32
+ });
package/bin/niral.js CHANGED
@@ -3,5 +3,14 @@
3
3
  // Available globally after `npm i -g create-niral`, or per-call via `npx niral dev`.
4
4
  import { ensureFramework, runNiral } from "../index.js";
5
5
 
6
- await ensureFramework();
7
- process.exit(runNiral(process.argv.slice(2)));
6
+ async function main() {
7
+ await ensureFramework();
8
+ return runNiral(process.argv.slice(2));
9
+ }
10
+
11
+ main().then((code) => {
12
+ process.exitCode = code;
13
+ }).catch((error) => {
14
+ console.error(`niral: ${error?.message || error}`);
15
+ process.exitCode = 1;
16
+ });
package/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { existsSync, mkdirSync, rmSync, writeFileSync, chmodSync, appendFileSync, readFileSync } from "node:fs";
10
- import { spawnSync, execSync } from "node:child_process";
10
+ import { spawnSync } from "node:child_process";
11
11
  import { join } from "node:path";
12
12
  import { homedir } from "node:os";
13
13
  import { get } from "node:https";
@@ -33,12 +33,23 @@ function download(url, dest) {
33
33
  }
34
34
 
35
35
  function hasGit() {
36
- try {
37
- execSync("git --version", { stdio: "ignore" });
38
- return true;
39
- } catch {
40
- return false;
41
- }
36
+ const result = spawnSync("git", ["--version"], { stdio: "ignore" });
37
+ return !result.error && result.status === 0;
38
+ }
39
+
40
+ function commandError(label, result) {
41
+ const detail = result.error?.message || result.stderr?.trim() || `exit ${result.status ?? "unknown"}`;
42
+ return new Error(`${label} failed: ${detail}`);
43
+ }
44
+
45
+ async function installFromTarball() {
46
+ const tgz = join(NIRAL_HOME, "niral.tgz");
47
+ await download(TARBALL, tgz);
48
+ rmSync(FRAMEWORK, { recursive: true, force: true });
49
+ mkdirSync(FRAMEWORK, { recursive: true });
50
+ const extracted = spawnSync("tar", ["-xzf", tgz, "-C", FRAMEWORK, "--strip-components=1"], { encoding: "utf8" });
51
+ rmSync(tgz, { force: true });
52
+ if (extracted.error || extracted.status !== 0) throw commandError("framework extraction", extracted);
42
53
  }
43
54
 
44
55
  /** Download the framework to ~/.niral/framework (git if available, tarball otherwise). */
@@ -46,21 +57,22 @@ export async function ensureFramework({ update = false } = {}) {
46
57
  if (existsSync(join(FRAMEWORK, "bin", "niral.js")) && !update) return FRAMEWORK;
47
58
  console.log("niral · downloading the framework (one time, ~1 MB — it has zero dependencies)…");
48
59
  mkdirSync(NIRAL_HOME, { recursive: true });
60
+ let installed = false;
49
61
  if (hasGit()) {
50
- if (existsSync(join(FRAMEWORK, ".git"))) {
51
- execSync("git pull -q", { cwd: FRAMEWORK, stdio: "ignore" });
62
+ const gitResult = existsSync(join(FRAMEWORK, ".git"))
63
+ ? spawnSync("git", ["pull", "--ff-only", "-q"], { cwd: FRAMEWORK, encoding: "utf8" })
64
+ : (() => {
65
+ rmSync(FRAMEWORK, { recursive: true, force: true });
66
+ return spawnSync("git", ["clone", "-q", "--depth", "1", REPO, FRAMEWORK], { encoding: "utf8" });
67
+ })();
68
+ if (!gitResult.error && gitResult.status === 0) {
69
+ installed = true;
52
70
  } else {
53
- rmSync(FRAMEWORK, { recursive: true, force: true });
54
- execSync(`git clone -q --depth 1 ${REPO} "${FRAMEWORK}"`, { stdio: "ignore" });
71
+ const reason = gitResult.error?.message || gitResult.stderr?.trim() || `exit ${gitResult.status ?? "unknown"}`;
72
+ console.warn(`niral · Git download unavailable (${reason}); trying the release tarball…`);
55
73
  }
56
- } else {
57
- const tgz = join(NIRAL_HOME, "niral.tgz");
58
- await download(TARBALL, tgz);
59
- rmSync(FRAMEWORK, { recursive: true, force: true });
60
- mkdirSync(FRAMEWORK, { recursive: true });
61
- execSync(`tar -xzf "${tgz}" -C "${FRAMEWORK}" --strip-components=1`, { stdio: "ignore" });
62
- rmSync(tgz);
63
74
  }
75
+ if (!installed) await installFromTarball();
64
76
  if (!existsSync(join(FRAMEWORK, "bin", "niral.js"))) throw new Error("framework download failed — try again or clone github.com/Zyora-Dev/niral manually");
65
77
  return FRAMEWORK;
66
78
  }
@@ -69,9 +81,14 @@ export async function ensureFramework({ update = false } = {}) {
69
81
  export function installLauncher() {
70
82
  const binDir = join(NIRAL_HOME, "bin");
71
83
  mkdirSync(binDir, { recursive: true });
72
- const shim = join(binDir, "niral");
73
- writeFileSync(shim, `#!/usr/bin/env bash\nexec node "${join(FRAMEWORK, "bin", "niral.js")}" "$@"\n`);
74
- chmodSync(shim, 0o755);
84
+ const frameworkCli = join(FRAMEWORK, "bin", "niral.js");
85
+ const shim = join(binDir, process.platform === "win32" ? "niral.cmd" : "niral");
86
+ if (process.platform === "win32") {
87
+ writeFileSync(shim, `@echo off\r\n"${process.execPath}" "${frameworkCli}" %*\r\n`);
88
+ } else {
89
+ writeFileSync(shim, `#!/usr/bin/env sh\nexec "${process.execPath}" "${frameworkCli}" "$@"\n`);
90
+ chmodSync(shim, 0o755);
91
+ }
75
92
 
76
93
  const profile =
77
94
  (process.env.SHELL ?? "").endsWith("/zsh") ? join(homedir(), ".zshrc")
@@ -91,6 +108,9 @@ export function installLauncher() {
91
108
 
92
109
  /** Forward a command to the framework CLI. */
93
110
  export function runNiral(args) {
94
- const r = spawnSync("node", [join(FRAMEWORK, "bin", "niral.js"), ...args], { stdio: "inherit" });
95
- return r.status ?? 0;
111
+ const r = spawnSync(process.execPath, [join(FRAMEWORK, "bin", "niral.js"), ...args], { stdio: "inherit" });
112
+ if (r.error) throw new Error(`could not start the Niral CLI: ${r.error.message}`);
113
+ if (r.signal) throw new Error(`Niral CLI terminated by ${r.signal}`);
114
+ if (r.status === null) throw new Error("Niral CLI exited without a status");
115
+ return r.status;
96
116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niral",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Niral — the zero-dependency full-stack framework by ZyoraLabs. This package is a tiny launcher; the framework itself lives at github.com/Zyora-Dev/niral and has zero dependencies.",
5
5
  "bin": {
6
6
  "niral": "bin/niral.js",