create-innovator 0.4.1 → 1.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.
Files changed (3) hide show
  1. package/README.md +163 -0
  2. package/dist/cli.js +19 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1 +1,164 @@
1
+ # create-innovator
2
+
1
3
  [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
4
+
5
+ A CLI scaffolding tool that creates new projects from the Storm Reply [innovator-template](https://github.com/stormreply/innovator-template). It clones the template repository, replaces placeholder names with your project name, installs dependencies, and creates an initial commit — all in one command.
6
+
7
+ ## Prerequisites
8
+
9
+ - [Node.js](https://nodejs.org/) >= 24
10
+ - [pnpm](https://pnpm.io/) >= 10.29.2 (or corepack will enable it automatically)
11
+ - [GitHub CLI (`gh`)](https://cli.github.com/) installed and available on your `PATH`
12
+ - A **GitHub Personal Access Token** with `repo` and `read:packages` scopes and access to the `stormreply` organization
13
+
14
+ ## Usage
15
+
16
+ Run directly with pnpm:
17
+
18
+ ```bash
19
+ pnpm create innovator
20
+ ```
21
+
22
+ Or with npx:
23
+
24
+ ```bash
25
+ npx create-innovator
26
+ ```
27
+
28
+ ### Options
29
+
30
+ | Flag | Alias | Description |
31
+ | ---------------- | ----- | ----------------------------------------------------------- |
32
+ | `--name <name>` | `-n` | Project name (skips the interactive prompt) |
33
+ | `--latest` | `-l` | Skip version selection and use the latest version |
34
+ | `--experimental` | `-e` | Include pre-release template versions in the version picker |
35
+
36
+ ### Examples
37
+
38
+ Create a project interactively:
39
+
40
+ ```bash
41
+ pnpm create innovator
42
+ ```
43
+
44
+ Create a project with a specific name:
45
+
46
+ ```bash
47
+ pnpm create innovator --name my-project
48
+ ```
49
+
50
+ Use the latest template version without prompting:
51
+
52
+ ```bash
53
+ pnpm create innovator --latest
54
+ ```
55
+
56
+ Include experimental template versions:
57
+
58
+ ```bash
59
+ pnpm create innovator --experimental
60
+ ```
61
+
62
+ ### What happens when you run it
63
+
64
+ 1. **GitHub authentication** — reads your token from `~/.npmrc` or prompts you to enter one. Validates required scopes (`repo`, `read:packages`) and access to the `stormreply` organization.
65
+ 2. **Version selection** — fetches available template tags and lets you pick a version (or auto-selects the latest when `--latest` is used).
66
+ 3. **Clone** — shallow-clones the template at the selected tag using `gh repo clone`, then re-initializes a fresh git repository.
67
+ 4. **Name replacement** — replaces `innovator-template` throughout the project with your chosen name in all case variants (kebab-case, camelCase, PascalCase, Title Case).
68
+ 5. **Template cleanup** — removes template-specific files that are not needed in the new project.
69
+ 6. **Setup** — installs dependencies via `pnpm install`, updates test snapshots, and creates an initial commit.
70
+
71
+ If the automatic setup fails, the CLI prints the commands to run manually.
72
+
73
+ ---
74
+
75
+ ## Development
76
+
77
+ ### Getting started
78
+
79
+ ```bash
80
+ git clone git@github.com:stormreply/create-innovator.git
81
+ cd create-innovator
82
+ pnpm install
83
+ ```
84
+
85
+ ### Scripts
86
+
87
+ ```bash
88
+ pnpm dev # Run the CLI locally via tsx
89
+ pnpm build # Build with tsup (outputs to dist/)
90
+ pnpm test # Run all tests (vitest)
91
+ pnpm test:watch # Run tests in watch mode
92
+ pnpm lint # ESLint
93
+ pnpm format # Prettier (write mode)
94
+ ```
95
+
96
+ Run a single test file:
97
+
98
+ ```bash
99
+ pnpm test -- src/scaffold/clone.test.ts
100
+ ```
101
+
102
+ ### Project structure
103
+
104
+ ```
105
+ src/
106
+ ├── cli.ts # Entry point — arg parsing (citty) and interactive UI (@clack/prompts)
107
+ ├── cli.test.ts
108
+ ├── auth/
109
+ │ ├── github.ts # Token validation, scope + org access checks
110
+ │ ├── github.test.ts
111
+ │ ├── prompts.ts # Interactive token input
112
+ │ ├── prompts.test.ts
113
+ │ ├── token-storage.ts # Read/write token from ~/.npmrc
114
+ │ └── token-storage.test.ts
115
+ ├── scaffold/
116
+ │ ├── clone.ts # gh CLI check, tag fetching, shallow clone + git init
117
+ │ ├── clone.test.ts
118
+ │ ├── template.ts # Name replacement engine + template file cleanup
119
+ │ ├── template.test.ts
120
+ │ ├── setup.ts # pnpm install, snapshot update, initial commit
121
+ │ └── setup.test.ts
122
+ └── utils/
123
+ ├── case.ts # PascalCase conversion (wraps Remeda)
124
+ ├── case.test.ts
125
+ └── constants.ts # GitHub org, repo, scopes, registry URL
126
+ ```
127
+
128
+ ### Code style
129
+
130
+ - **ESM** throughout (`"type": "module"`, `.js` extensions in imports)
131
+ - **TypeScript** with strict mode, target ES2022, NodeNext module resolution
132
+ - **Prettier**: single quotes, semicolons, trailing commas, 120 char line width
133
+ - **Dependencies** are pinned to exact versions (no `^` or `~` prefixes)
134
+
135
+ ### Testing
136
+
137
+ Tests use [Vitest](https://vitest.dev/) with `globals: true` — no imports needed for `describe`, `it`, `expect`, or `vi`.
138
+
139
+ Key patterns:
140
+
141
+ - Shell commands (`child_process.execFile`) are mocked via `vi.mock('node:child_process')` with callback-style mocks
142
+ - File system operations in template tests use [`memfs`](https://github.com/nicknisi/memfs) (in-memory filesystem)
143
+ - `@clack/prompts` is mocked in most test files to suppress UI output
144
+
145
+ ### Git hooks (Husky)
146
+
147
+ | Hook | Action |
148
+ | -------------------- | -------------------------------------------------------------------------------------------------------- |
149
+ | `pre-commit` | Runs lint-staged — ESLint + Prettier on staged `*.{js,json,md,ts}` files, vitest on related `*.ts` files |
150
+ | `prepare-commit-msg` | Launches Commitizen interactively to guide you through a conventional commit message |
151
+ | `commit-msg` | Enforces [Conventional Commits](https://www.conventionalcommits.org/) via commitlint |
152
+ | `pre-push` | Runs the full test suite (only if working tree is clean) |
153
+
154
+ ### Commits
155
+
156
+ This project follows [Conventional Commits](https://www.conventionalcommits.org/) and is [Commitizen](http://commitizen.github.io/cz-cli/) friendly. The `prepare-commit-msg` hook automatically launches Commitizen when you run `git commit`, guiding you through a structured commit message prompt — no extra commands needed.
157
+
158
+ ### Releasing
159
+
160
+ Releases are managed with [release-it](https://github.com/release-it/release-it):
161
+
162
+ ```bash
163
+ pnpm release
164
+ ```
package/dist/cli.js CHANGED
@@ -209,6 +209,17 @@ async function fetchReleaseTags(token, includeExperimental = false) {
209
209
  }
210
210
  return tags;
211
211
  }
212
+ async function selectLatestVersion(token, includeExperimental = false) {
213
+ const s = p3.spinner();
214
+ s.start("Fetching latest template version");
215
+ const tags = await fetchReleaseTags(token, includeExperimental);
216
+ if (tags.length === 0) {
217
+ s.stop("No versions found");
218
+ throw new Error(`No release tags found in ${GITHUB_ORG}/${TEMPLATE_REPO}.`);
219
+ }
220
+ s.stop(`Using latest version: ${tags[0]}`);
221
+ return tags[0];
222
+ }
212
223
  async function selectVersion(token, includeExperimental = false) {
213
224
  const s = p3.spinner();
214
225
  s.start("Fetching available template versions");
@@ -372,6 +383,13 @@ var main = defineCommand({
372
383
  required: false,
373
384
  type: "string"
374
385
  },
386
+ latest: {
387
+ alias: ["l"],
388
+ description: "Skip version selection and use the latest version",
389
+ required: false,
390
+ type: "boolean",
391
+ default: false
392
+ },
375
393
  experimental: {
376
394
  alias: ["e"],
377
395
  description: "Include experimental (pre-release) versions",
@@ -394,7 +412,7 @@ var main = defineCommand({
394
412
  try {
395
413
  const token = await ensureGitHubAuth();
396
414
  await ensureGhCli();
397
- const tag = await selectVersion(token, args.experimental);
415
+ const tag = args.latest ? await selectLatestVersion(token, args.experimental) : await selectVersion(token, args.experimental);
398
416
  await cloneTemplate(projectName, tag);
399
417
  await replaceTemplateNames(projectName, projectName);
400
418
  await removeTemplateFiles(projectName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-innovator",
3
- "version": "0.4.1",
3
+ "version": "1.1.0",
4
4
  "description": "Create Innovator App",
5
5
  "author": {
6
6
  "email": "storm@reply.de",