genrex 0.1.0 → 0.2.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 CHANGED
@@ -11,7 +11,7 @@
11
11
  </p>
12
12
 
13
13
  <p align="center">
14
- <img src="https://img.shields.io/badge/version-0.1.0-blue?style=flat-square" alt="Version" />
14
+ <img src="https://img.shields.io/badge/version-0.2.0-blue?style=flat-square" alt="Version" />
15
15
  <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License" />
16
16
  </p>
17
17
 
@@ -6,21 +6,37 @@ import { buildNodeApiFiles } from "./generators/node-api.js";
6
6
  import { buildTsLibFiles } from "./generators/ts-lib.js";
7
7
  import { checkGit, initGit } from "./git.js";
8
8
  import { installDependencies } from "./pm.js";
9
- export function createProject(name, options) {
10
- if (!name) {
9
+ import { promptWizard } from "./prompt.js";
10
+ export async function createProject(name, options) {
11
+ let targetName = name;
12
+ let targetBlueprint = options.blueprint ?? "ts-cli";
13
+ let targetPm = options.packageManager ?? "pnpm";
14
+ let targetGit = options.git;
15
+ let targetCi = options.githubActions;
16
+ let targetDocker = options.docker;
17
+ if ((!targetName || options.interactive) && process.stdin.isTTY) {
18
+ const answers = await promptWizard(targetName);
19
+ targetName = answers.name;
20
+ targetBlueprint = answers.blueprint;
21
+ targetPm = answers.packageManager;
22
+ targetGit = answers.git;
23
+ targetCi = answers.githubActions;
24
+ targetDocker = answers.docker;
25
+ }
26
+ if (!targetName) {
11
27
  fail("Project name is required. Example: genrex create my-project");
12
28
  return;
13
29
  }
14
30
  const config = {
15
- name: basename(name),
16
- destination: resolve(name),
17
- blueprint: options.blueprint ?? "ts-cli",
18
- packageManager: options.packageManager ?? "pnpm",
31
+ name: basename(targetName),
32
+ destination: resolve(targetName),
33
+ blueprint: targetBlueprint,
34
+ packageManager: targetPm,
19
35
  testing: "vitest",
20
36
  formatter: "biome",
21
- git: options.git,
22
- githubActions: options.githubActions,
23
- docker: options.docker,
37
+ git: targetGit,
38
+ githubActions: targetCi,
39
+ docker: targetDocker,
24
40
  };
25
41
  const errors = validateConfig(config);
26
42
  const blueprint = getBlueprint(config.blueprint);
@@ -57,16 +73,16 @@ export function createProject(name, options) {
57
73
  console.log(`Blueprint: ${blueprint.name}`);
58
74
  console.log(`Destination: ${config.destination}`);
59
75
  console.log(`Package manager: ${config.packageManager}`);
60
- console.log(`Git: ${options.git ? "yes" : "no"}`);
61
- console.log(`GitHub Actions: ${options.githubActions ? "yes" : "no"}`);
62
- console.log(`Docker: ${options.docker ? "yes" : "no"}`);
76
+ console.log(`Git: ${config.git ? "yes" : "no"}`);
77
+ console.log(`GitHub Actions: ${config.githubActions ? "yes" : "no"}`);
78
+ console.log(`Docker: ${config.docker ? "yes" : "no"}`);
63
79
  console.log("\nWould create:");
64
80
  for (const f of files) {
65
81
  console.log(` - ${f.path}`);
66
82
  }
67
83
  console.log("\nWould install:");
68
84
  console.log(" devDependencies: typescript, vitest, @biomejs/biome, @types/node");
69
- if (options.git) {
85
+ if (config.git) {
70
86
  console.log("\nWould execute:");
71
87
  console.log(" git init");
72
88
  }
@@ -84,13 +100,13 @@ export function createProject(name, options) {
84
100
  installDependencies(config.packageManager, config.destination);
85
101
  console.log("✓ Dependencies installed");
86
102
  }
87
- if (options.git) {
103
+ if (config.git) {
88
104
  console.log("Initializing Git repository...");
89
105
  initGit(config.destination);
90
106
  console.log("✓ Git repository initialized");
91
107
  }
92
108
  console.log("\nDone. Next steps:");
93
- console.log(` cd ${name}`);
109
+ console.log(` cd ${targetName}`);
94
110
  if (options.skipInstall) {
95
111
  console.log(` ${config.packageManager} install`);
96
112
  }
package/dist/src/index.js CHANGED
@@ -5,7 +5,7 @@ import { blueprints, getBlueprint } from "./blueprints.js";
5
5
  const [command, ...args] = process.argv.slice(2);
6
6
  switch (command) {
7
7
  case "create":
8
- runCreate(args);
8
+ await runCreate(args);
9
9
  break;
10
10
  case "list":
11
11
  listBlueprints();
@@ -23,24 +23,27 @@ switch (command) {
23
23
  break;
24
24
  case "--version":
25
25
  case "-v":
26
- console.log("0.1.0");
26
+ console.log("0.2.0");
27
27
  break;
28
28
  default:
29
29
  console.error(`Unknown command: ${command}`);
30
30
  console.error("Run 'genrex --help' for usage.");
31
31
  process.exitCode = 1;
32
32
  }
33
- function runCreate(args) {
34
- const [name, ...flags] = args;
33
+ async function runCreate(args) {
34
+ const [firstArg, ...flags] = args;
35
+ let name = firstArg?.startsWith("-") ? undefined : firstArg;
36
+ const allFlags = firstArg?.startsWith("-") ? [firstArg, ...flags] : flags;
35
37
  const options = {
36
38
  dryRun: false,
37
39
  skipInstall: false,
38
40
  git: false,
39
41
  githubActions: false,
40
42
  docker: false,
43
+ interactive: false,
41
44
  };
42
- for (let index = 0; index < flags.length; index += 1) {
43
- const flag = flags[index];
45
+ for (let index = 0; index < allFlags.length; index += 1) {
46
+ const flag = allFlags[index];
44
47
  if (flag === "--dry-run") {
45
48
  options.dryRun = true;
46
49
  }
@@ -56,11 +59,14 @@ function runCreate(args) {
56
59
  else if (flag === "--docker") {
57
60
  options.docker = true;
58
61
  }
62
+ else if (flag === "-i" || flag === "--interactive") {
63
+ options.interactive = true;
64
+ }
59
65
  else if (flag === "--blueprint") {
60
- options.blueprint = flags[++index];
66
+ options.blueprint = allFlags[++index];
61
67
  }
62
68
  else if (flag === "--package-manager") {
63
- const packageManager = flags[++index];
69
+ const packageManager = allFlags[++index];
64
70
  if (!["npm", "pnpm", "yarn", "bun"].includes(packageManager)) {
65
71
  console.error(`Error: Unsupported package manager '${packageManager}'.`);
66
72
  process.exitCode = 1;
@@ -74,7 +80,7 @@ function runCreate(args) {
74
80
  return;
75
81
  }
76
82
  }
77
- createProject(name, options);
83
+ await createProject(name, options);
78
84
  }
79
85
  function listBlueprints() {
80
86
  console.log("Available blueprints:\n");
@@ -111,19 +117,20 @@ Usage:
111
117
  genrex <command> [options]
112
118
 
113
119
  Commands:
120
+ create [name] Create a project (interactive wizard by default)
114
121
  list List available blueprints
115
122
  info <name> Show blueprint details
116
- create <name> --dry-run Preview project generation
117
123
  doctor Check local environment
118
124
 
119
125
  Create options:
120
- --blueprint <id> Blueprint ID (default: ts-cli)
126
+ -i, --interactive Launch interactive prompt wizard
127
+ --blueprint <id> Blueprint ID (ts-cli, node-api, ts-lib)
121
128
  --package-manager <manager> npm, pnpm, yarn, or bun (default: pnpm)
122
- --dry-run Preview without filesystem changes
123
- --skip-install Do not install dependencies
124
129
  --git Initialize a Git repository
125
130
  --github-actions Generate GitHub Actions CI workflow
126
131
  --docker Generate Dockerfile & .dockerignore
132
+ --dry-run Preview without filesystem changes
133
+ --skip-install Do not install dependencies
127
134
 
128
135
  Options:
129
136
  -h, --help Show help
@@ -0,0 +1,50 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { stdin, stdout } from "node:process";
3
+ import { blueprints } from "./blueprints.js";
4
+ export async function promptWizard(initialName) {
5
+ const rl = createInterface({ input: stdin, output: stdout });
6
+ try {
7
+ console.log("\ngenrex — Project Blueprint Engine\n");
8
+ let name = initialName;
9
+ while (!name || name.trim() === "") {
10
+ const answer = await rl.question("? Project name: ");
11
+ name = answer.trim();
12
+ if (!name) {
13
+ console.log(" Project name cannot be empty.");
14
+ }
15
+ }
16
+ console.log("\n? Choose a blueprint:");
17
+ blueprints.forEach((b, i) => {
18
+ console.log(` ${i + 1}) ${b.name.padEnd(22)} (${b.id})`);
19
+ });
20
+ const bpChoice = await rl.question(`Select [1-${blueprints.length}] (1): `);
21
+ const bpIndex = Number.parseInt(bpChoice.trim() || "1", 10) - 1;
22
+ const blueprint = (blueprints[bpIndex] ?? blueprints[0]).id;
23
+ const pms = ["pnpm", "npm", "yarn", "bun"];
24
+ console.log("\n? Package manager:");
25
+ pms.forEach((pm, i) => {
26
+ console.log(` ${i + 1}) ${pm}`);
27
+ });
28
+ const pmChoice = await rl.question(`Select [1-${pms.length}] (1): `);
29
+ const pmIndex = Number.parseInt(pmChoice.trim() || "1", 10) - 1;
30
+ const packageManager = pms[pmIndex] ?? "pnpm";
31
+ const gitAns = await rl.question("\n? Initialize Git? (Y/n): ");
32
+ const git = gitAns.trim().toLowerCase() !== "n";
33
+ const ciAns = await rl.question("? Add GitHub Actions CI? (y/N): ");
34
+ const githubActions = ciAns.trim().toLowerCase() === "y";
35
+ const dockerAns = await rl.question("? Add Docker? (y/N): ");
36
+ const docker = dockerAns.trim().toLowerCase() === "y";
37
+ console.log();
38
+ return {
39
+ name,
40
+ blueprint,
41
+ packageManager,
42
+ git,
43
+ githubActions,
44
+ docker,
45
+ };
46
+ }
47
+ finally {
48
+ rl.close();
49
+ }
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genrex",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Forge production-ready TypeScript projects from blueprints",
5
5
  "license": "MIT",
6
6
  "type": "module",