@cnpx/cnpx 0.0.4-dev.20260403235918 → 0.0.4-dev.20260404115856

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
@@ -1,107 +1,333 @@
1
- # @cnpx/cnpx
1
+ # cnpx — Project Scaffolder
2
2
 
3
- `@cnpx/cnpx` is an interactive CLI that scaffolds projects from the
4
- [`xcfio/template`](https://github.com/xcfio/template) repository.
3
+ An interactive CLI tool for creating new projects from curated templates hosted on GitHub. Pick a category, pick a template, and get coding.
5
4
 
6
- It fetches available categories and templates from GitHub, clones your selected
7
- template into a local directory, and prints the next commands to run.
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [CLI Flags](#cli-flags)
12
+ - [Interactive Flow](#interactive-flow)
13
+ - [Templates](#templates)
14
+ - [Package Manager Detection](#package-manager-detection)
15
+ - [Auto-Update Check](#auto-update-check)
16
+ - [Validation](#validation)
17
+ - [Dependencies](#dependencies)
18
+ - [Development](#development)
19
+ - [Links & Community](#links--community)
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ Install globally to use the `cnpx` command from anywhere.
8
26
 
9
- ## Features
27
+ **pnpm**
10
28
 
11
- - Interactive prompts for project name, category, and template
12
- - Live template discovery from `xcfio/template`
13
- - Automatic package manager detection (`pnpm`, `yarn`, then `npm`)
14
- - Update notification when a newer package version exists on npm
29
+ ```bash
30
+ pnpm install -g @cnpx/cnpx
31
+ ```
15
32
 
16
- ## Requirements
33
+ **npm**
17
34
 
18
- - Node.js 22+
19
- - Internet access (GitHub API + npm registry)
35
+ ```bash
36
+ npm install -g @cnpx/cnpx
37
+ ```
38
+
39
+ **yarn**
40
+
41
+ ```bash
42
+ yarn global add @cnpx/cnpx
43
+ ```
20
44
 
21
- ## Usage
45
+ > **Requires Node.js 22.5 or later.** Check your version with `node --version`.
22
46
 
23
- Run directly without installing globally:
47
+ Alternatively, run without installing:
24
48
 
25
49
  ```bash
26
50
  npx @cnpx/cnpx
27
- # or
28
- pnpm dlx @cnpx/cnpx
29
- # or
30
- yarn dlx @cnpx/cnpx
31
51
  ```
32
52
 
33
- Then follow the prompts:
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ > **Important:** The `cnpx` command works only if `@cnpx/cnpx` is installed globally. If you have not installed it globally, use `npx @cnpx/cnpx` instead.
34
58
 
35
- 1. Enter project name
36
- 2. Select a category (for example: `backend`, `frontend`)
37
- 3. Select a template
38
- 4. Confirm creation
59
+ Run `cnpx` with no arguments to launch the fully interactive prompt wizard:
60
+
61
+ ```bash
62
+ cnpx
63
+ ```
39
64
 
40
- After scaffold, the CLI prints:
65
+ Or skip straight to a known template with flags:
41
66
 
42
67
  ```bash
43
- cd <project-name>
44
- <detected-package-manager> install
45
- node --run dev
68
+ cnpx --name my-app --template nextjs/starter
46
69
  ```
47
70
 
48
- ## Global Install (Optional)
71
+ ---
72
+
73
+ ## CLI Flags
74
+
75
+ All flags are optional. Any omitted value is collected interactively.
76
+
77
+ | Flag | Type | Description |
78
+ | ------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
79
+ | `-n`, `--name` | `string` | Output directory / project name. Validated against filesystem rules — see [Validation](#validation). |
80
+ | `-c`, `--category` | `string` | Template category (top-level directory in the template repo). Skips the category selection prompt. |
81
+ | `-t`, `--template` | `string` | Template name. Accepts bare name (`starter`) or `category/template` slash syntax. Slash syntax also sets `--category`. |
82
+ | `-f`, `--force` | `boolean` | Overwrite a non-empty target directory without prompting. Skips both the overwrite confirmation and the final "create project?" confirmation. |
83
+ | `-h`, `--help` | `boolean` | Print the help message and exit. Also triggered by passing `help` as a bare argument. |
84
+
85
+ ### Examples
49
86
 
50
87
  ```bash
51
- npm i -g @cnpx/cnpx
88
+ # Fully interactive
52
89
  cnpx
90
+
91
+ # Name only — prompts for category and template
92
+ cnpx --name my-project
93
+
94
+ # Slash syntax — sets both category and template
95
+ cnpx -t nextjs/starter
96
+
97
+ # Category and template as separate flags
98
+ cnpx --category nextjs --template starter
99
+
100
+ # All flags — no prompts at all
101
+ cnpx -n my-app -t nextjs/starter -f
102
+
103
+ # Print help
104
+ cnpx --help
105
+ ```
106
+
107
+ > **Note:** Unknown flags are silently ignored (`strict: false` parse mode). Only the flags listed above have any effect.
108
+
109
+ ---
110
+
111
+ ## Interactive Flow
112
+
113
+ When flags are omitted the CLI walks through a series of prompts in order:
114
+
53
115
  ```
116
+ update check → project name → overwrite? → category → template → confirm → clone
117
+ ```
118
+
119
+ 1. **Update check** — silently queries the npm registry. If a newer version of `@cnpx/cnpx` exists, a note is shown with the upgrade command. Non-blocking.
120
+
121
+ 2. **Project name** — free-text prompt with default `my-project`. Validated in real-time. Skipped when `--name` is provided.
54
122
 
55
- ## Programmatic API
123
+ 3. **Overwrite confirmation** — shown only when the target directory already exists _and_ is non-empty. Cancelling aborts. Skipped when `--force` is set.
56
124
 
57
- This package also exports utility functions:
125
+ 4. **Category selection** fetches top-level directories from the GitHub template repo and presents a `select` list. Skipped when `--category` or a slash-template is provided.
58
126
 
59
- - `main()`
60
- - `checkForUpdate()`
61
- - `clone(name, category, template)`
62
- - `getCategories()`
63
- - `getTemplates(category)`
64
- - `getPackageManager()`
65
- - `get(url)`
127
+ 5. **Template selection** — fetches sub-directories for the chosen category. Skipped when `--template` is provided.
66
128
 
67
- Type exports:
129
+ 6. **Final confirmation** — summarises name, category, and template before cloning. Skipped when `--force` is set.
68
130
 
69
- - `FilteredGithubResponse`
70
- - `GithubAPIResponse`
131
+ 7. **Clone** — degit clones the template into the target directory, caching the result locally for faster re-runs.
132
+
133
+ > Pressing `Ctrl+C` at any prompt cancels cleanly with an "Operation cancelled" message and exits with code `0`.
134
+
135
+ ---
136
+
137
+ ## Templates
138
+
139
+ All templates live in the [xcfio/template](https://github.com/xcfio/template) GitHub repository. The directory structure is:
140
+
141
+ ```
142
+ xcfio/template
143
+ ├── <category>/
144
+ │ ├── <template-name>/
145
+ │ │ └── ... template files
146
+ │ └── <template-name>/
147
+ └── <category>/
148
+ └── ...
149
+ ```
150
+
151
+ The following top-level directories are always excluded from the category list:
152
+
153
+ - `.github`
154
+ - `cnpx`
155
+
156
+ Templates are cloned using **degit** with `cache: true`, so repeated clones of the same template are served from a local cache instead of re-downloading from GitHub.
157
+
158
+ > **API rate limits:** Template lists are fetched live from the GitHub Contents API. If you encounter `API rate limit exceeded`, wait a few minutes and try again. Authenticated requests are not currently supported.
159
+
160
+ ---
161
+
162
+ ## Package Manager Detection
163
+
164
+ cnpx auto-detects the best available package manager by probing in priority order:
165
+
166
+ ```
167
+ pnpm → yarn → npm
168
+ ```
169
+
170
+ Detection runs `pnpm --version` and `yarn --version` via `execSync`. The first one that succeeds wins. The result is cached after the first call so subsequent lookups are free.
171
+
172
+ The detected package manager is used in:
173
+
174
+ - The update-available note (`run: <pm> i -g @cnpx/cnpx`)
175
+ - The post-clone "get started" instructions
176
+
177
+ ---
178
+
179
+ ## Auto-Update Check
180
+
181
+ At startup, cnpx fetches the latest version from the npm registry:
182
+
183
+ ```
184
+ GET https://registry.npmjs.org/@cnpx/cnpx/latest
185
+ ```
186
+
187
+ Versions are compared with a custom semver parser that handles pre-release identifiers correctly (numeric parts compared numerically, string parts lexicographically). If the remote version is _newer_ than the running version, a note is displayed:
188
+
189
+ ```
190
+ ┌ Update available ───────────────╮
191
+ │ │
192
+ │ Current: 0.0.4 → Latest: 0.0.5 │
193
+ │ Run: pnpm i -g @cnpx/cnpx │
194
+ │ │
195
+ └──────────────────────────────────╯
196
+ ```
197
+
198
+ The check is non-blocking — any error (network failure, rate limit) is silently swallowed so it never interrupts the main flow.
199
+
200
+ ---
201
+
202
+ ## Validation
203
+
204
+ ### Directory name rules
205
+
206
+ The project name is validated before any I/O happens. The following conditions cause an error:
207
+
208
+ | Rule | Error message |
209
+ | --------------------------------------------------------------------------- | -------------------------------------------------------- |
210
+ | Empty or only whitespace | `Directory name cannot be empty` |
211
+ | Longer than 255 characters | `Directory name is too long` |
212
+ | Contains `< > : " / \ \| ? *` or control characters | `Directory name contains invalid characters` |
213
+ | Starts or ends with `.` or a space | `Directory name cannot start or end with a dot or space` |
214
+ | Windows reserved names (`CON`, `PRN`, `AUX`, `NUL`, `COM0`–`9`, `LPT0`–`9`) | `Directory name is a reserved name` |
215
+
216
+ ### Target path rules
217
+
218
+ After name validation, the resolved path is checked:
219
+
220
+ | Condition | Behaviour |
221
+ | -------------------------------- | ---------------------------------------------------------------- |
222
+ | Path does not exist | Proceeds normally |
223
+ | Path is an empty directory | Proceeds normally (no overwrite prompt) |
224
+ | Path is a non-empty directory | Overwrite confirmation prompt (or auto-continues with `--force`) |
225
+ | Path is a file (not a directory) | Hard error — exits with code `1` |
226
+
227
+ ### Exit codes
228
+
229
+ | Code | Meaning |
230
+ | ---- | ----------------------------------------------------------------------------- |
231
+ | `0` | Success or user-cancelled |
232
+ | `1` | Validation error, target-is-file error, API rate limit, or uncaught exception |
233
+
234
+ ---
235
+
236
+ ## Dependencies
237
+
238
+ ### Runtime
239
+
240
+ | Package | Version | Purpose |
241
+ | ---------------- | --------- | ---------------------------------------------------------------------------------- |
242
+ | `@clack/prompts` | `^1.2.0` | Beautiful interactive prompts — text, select, confirm, spinner, note, outro |
243
+ | `colorette` | `^2.0.20` | Zero-dependency terminal colour helpers (`blue`, `green`, `bold`, `dim`, `yellow`) |
244
+ | `degit` | `^2.8.4` | Fast git-based scaffolding without cloning full history; supports local caching |
245
+
246
+ ### Dev / Build
247
+
248
+ | Package | Version | Purpose |
249
+ | -------------- | --------- | -------------------------------------------------------------------- |
250
+ | `tsup` | `^8.5.1` | Zero-config TypeScript bundler; outputs CJS (`.js`) and ESM (`.mjs`) |
251
+ | `@types/degit` | `^2.8.6` | TypeScript types for degit |
252
+ | `@types/node` | `^25.5.2` | TypeScript types for Node.js built-in APIs |
253
+
254
+ All runtime dependencies are pure-JS and work without native addons.
255
+
256
+ ---
71
257
 
72
258
  ## Development
73
259
 
74
- From `cnpx/cnpx`:
260
+ ### Project structure
75
261
 
76
- ```bash
77
- node --run install
78
- node --run dev
79
- node --run build
80
- node --run test
262
+ ```
263
+ src/
264
+ ├── bin.ts # Entry point — wires showHelp + main
265
+ ├── main.ts # Orchestrates the full interactive flow
266
+ ├── clone.ts # Wraps degit clone with a spinner
267
+ ├── checkForUpdate.ts # npm registry version check + semver comparison
268
+ ├── getCategories.ts # GitHub API → category list
269
+ ├── getTemplates.ts # GitHub API → template list for a category
270
+ ├── getPackageManager.ts # pnpm / yarn / npm detection (cached)
271
+ ├── isInvalidPath.ts # Target path existence and type checks
272
+ ├── isValidDirectoryName.ts # Name validation logic
273
+ ├── fetch.ts # Thin fetch wrapper returning typed JSON
274
+ └── showHelp.ts # --help output
81
275
  ```
82
276
 
83
- Available scripts:
277
+ ### npm scripts
84
278
 
85
- - `node --run fmt` - format source with Prettier
86
- - `node --run lint` - check formatting
87
- - `node --run dev` - build in watch mode with tsup
88
- - `node --run build` - production build
89
- - `node --run test` - type-check with `tsc --noEmit`
279
+ | Script | What it does |
280
+ | ------------------ | -------------------------------------------------------- |
281
+ | `node --run dev` | Runs `tsup --watch` rebuilds on every file change |
282
+ | `node --run build` | Runs `tsup` — produces the `out/` directory |
283
+ | `node --run test` | Runs `tsc --noEmit` — type-checks without emitting files |
284
+ | `node --run lint` | Checks formatting with Prettier |
285
+ | `node --run fmt` | Auto-formats all source files with Prettier |
90
286
 
91
- ## Notes and Limitations
287
+ ### Module format
92
288
 
93
- - The CLI is currently fully interactive and does not expose command-line flags.
94
- - GitHub API rate limits can block category/template loading.
289
+ The package sets `"type": "commonjs"` but ships both CJS (`index.js`) and ESM (`index.mjs`) via the `exports` map, so it works with both `require()` and `import`.
95
290
 
96
- ## Support
291
+ ```json
292
+ "exports": {
293
+ ".": {
294
+ "import": "./out/index.mjs",
295
+ "require": "./out/index.js"
296
+ }
297
+ }
298
+ ```
97
299
 
98
- - Issues: [GitHub Issues](https://github.com/xcfio/template/issues)
99
- - Discord: [Discord Server](https://discord.gg/FaCCaFM74Q)
300
+ ### Publishing
100
301
 
101
- ## License
302
+ The package is published publicly to npm under the `latest` tag:
102
303
 
103
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
304
+ ```json
305
+ "publishConfig": {
306
+ "access": "public",
307
+ "tag": "latest"
308
+ }
309
+ ```
310
+
311
+ ---
312
+
313
+ ## Links & Community
314
+
315
+ | Resource | URL |
316
+ | ----------------- | ------------------------------------------------------------ |
317
+ | GitHub repository | https://github.com/xcfio/template |
318
+ | npm package | https://www.npmjs.com/package/@cnpx/cnpx |
319
+ | Homepage | https://github.com/xcfio/template/tree/main/cnpx/cnpx#readme |
320
+ | Bug reports | https://github.com/xcfio/template/issues |
321
+ | Bug report email | omarfaruksxp@gmail.com |
322
+
323
+ ### Discord
324
+
325
+ Join the community on Discord for help, template sharing, and discussion:
326
+
327
+ **https://discord.gg/FaCCaFM74Q**
104
328
 
105
329
  ---
106
330
 
107
331
  Made with ❤️ by [xcfio](https://github.com/xcfio)
332
+
333
+ _If cnpx saves you time, consider leaving a star on the [GitHub repo](https://github.com/xcfio/template)._
package/out/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var main=require('./main');var o=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var s=o(()=>{process.removeAllListeners("warning"),main.main().catch(r=>{console.error(r),process.exit(1);});});var bin = s();module.exports=bin;
2
+ 'use strict';var showHelp=require('./showHelp'),main=require('./main');var s=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var i=s(()=>{process.removeAllListeners("warning"),(process.argv.includes("help")||process.argv.includes("--help")||process.argv.includes("-h"))&&showHelp.showHelp(),main.main().catch(r=>{console.error(r),process.exit(1);});});var bin = i();module.exports=bin;
package/out/bin.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import {a}from'./chunk-A7RKGLUR.mjs';import {main}from'./main';var n=a(()=>{process.removeAllListeners("warning"),main().catch(e=>{console.error(e),process.exit(1);});});var bin = n();export{bin as default};
2
+ import {a}from'./chunk-A7RKGLUR.mjs';import {showHelp}from'./showHelp';import {main}from'./main';var c=a(()=>{process.removeAllListeners("warning"),(process.argv.includes("help")||process.argv.includes("--help")||process.argv.includes("-h"))&&showHelp(),main().catch(e=>{console.error(e),process.exit(1);});});var bin = c();export{bin as default};
@@ -1,3 +1,8 @@
1
+ import { ParsedSemver } from './type.mjs';
2
+
3
+ declare function parseSemver(value: string): ParsedSemver | null;
4
+ declare function compareIdentifier(left: string, right: string): number;
5
+ declare function compareSemver(left: string, right: string): number;
1
6
  declare function checkForUpdate(): Promise<void>;
2
7
 
3
- export { checkForUpdate };
8
+ export { checkForUpdate, compareIdentifier, compareSemver, parseSemver };
@@ -1,3 +1,8 @@
1
+ import { ParsedSemver } from './type.js';
2
+
3
+ declare function parseSemver(value: string): ParsedSemver | null;
4
+ declare function compareIdentifier(left: string, right: string): number;
5
+ declare function compareSemver(left: string, right: string): number;
1
6
  declare function checkForUpdate(): Promise<void>;
2
7
 
3
- export { checkForUpdate };
8
+ export { checkForUpdate, compareIdentifier, compareSemver, parseSemver };
@@ -1,2 +1,2 @@
1
- 'use strict';var getPackageManager=require('./getPackageManager'),package_json=require('../package.json'),prompts=require('@clack/prompts'),colorette=require('colorette'),fetch=require('./fetch');function f(n){const t=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(n);return t?{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),pre:t[4]?t[4].split("."):[]}:null}function h(n,t){const r=/^\d+$/.test(n),e=/^\d+$/.test(t);if(r&&e){const o=Number(n),i=Number(t);return o<i?-1:o>i?1:0}return r&&!e?-1:!r&&e?1:n<t?-1:n>t?1:0}function b(n,t){const r=f(n),e=f(t);if(!r||!e)return n.localeCompare(t,void 0,{numeric:true,sensitivity:"base"});if(r.major!==e.major)return r.major<e.major?-1:1;if(r.minor!==e.minor)return r.minor<e.minor?-1:1;if(r.patch!==e.patch)return r.patch<e.patch?-1:1;if(r.pre.length===0&&e.pre.length===0)return 0;if(r.pre.length===0)return 1;if(e.pre.length===0)return -1;const o=Math.max(r.pre.length,e.pre.length);for(let i=0;i<o;i++){const u=r.pre[i],a=e.pre[i];if(u===void 0)return -1;if(a===void 0)return 1;const m=h(u,a);if(m!==0)return m}return 0}async function P(){try{const{data:n}=await fetch.get(`https://registry.npmjs.org/${package_json.name}/latest`);if(b(n.version,package_json.version)<=0)return;prompts.note(`Current: ${colorette.bold(package_json.version)} \u2192 Latest: ${colorette.bold(n.version)}
2
- Run: ${getPackageManager.getPackageManager()} i -g ${package_json.name}`,"Update available");}catch{}}exports.checkForUpdate=P;
1
+ 'use strict';var getPackageManager=require('./getPackageManager'),package_json=require('../package.json'),prompts=require('@clack/prompts'),colorette=require('colorette'),fetch=require('./fetch');function f(n){const r=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(n);return r?{major:Number(r[1]),minor:Number(r[2]),patch:Number(r[3]),pre:r[4]?r[4].split("."):[]}:null}function b(n,r){const e=/^\d+$/.test(n),t=/^\d+$/.test(r);if(e&&t){const o=Number(n),i=Number(r);return o<i?-1:o>i?1:0}return e&&!t?-1:!e&&t?1:n<r?-1:n>r?1:0}function v(n,r){const e=f(n),t=f(r);if(!e||!t)return n.localeCompare(r,void 0,{numeric:true,sensitivity:"base"});if(e.major!==t.major)return e.major<t.major?-1:1;if(e.minor!==t.minor)return e.minor<t.minor?-1:1;if(e.patch!==t.patch)return e.patch<t.patch?-1:1;if(e.pre.length===0&&t.pre.length===0)return 0;if(e.pre.length===0)return 1;if(t.pre.length===0)return -1;const o=Math.max(e.pre.length,t.pre.length);for(let i=0;i<o;i++){const a=e.pre[i],u=t.pre[i];if(a===void 0)return -1;if(u===void 0)return 1;const m=b(a,u);if(m!==0)return m}return 0}async function k(){const n=prompts.spinner();n.start("Checking for updates");try{const{data:r}=await fetch.get(`https://registry.npmjs.org/${package_json.name}/latest`);if(v(r.version,package_json.version)<=0)return;prompts.note(`Current: ${colorette.bold(package_json.version)} \u2192 Latest: ${colorette.bold(r.version)}
2
+ Run: ${getPackageManager.getPackageManager()} i -g ${package_json.name}`,"Update available");}catch{}finally{n.clear();}}exports.checkForUpdate=k;exports.compareIdentifier=b;exports.compareSemver=v;exports.parseSemver=f;
@@ -1,2 +1,2 @@
1
- import'./chunk-A7RKGLUR.mjs';import {getPackageManager}from'./getPackageManager';import {name,version}from'../package.json';import {note}from'@clack/prompts';import {bold}from'colorette';import {get}from'./fetch';function f(n){const t=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(n);return t?{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),pre:t[4]?t[4].split("."):[]}:null}function h(n,t){const r=/^\d+$/.test(n),e=/^\d+$/.test(t);if(r&&e){const o=Number(n),i=Number(t);return o<i?-1:o>i?1:0}return r&&!e?-1:!r&&e?1:n<t?-1:n>t?1:0}function b(n,t){const r=f(n),e=f(t);if(!r||!e)return n.localeCompare(t,void 0,{numeric:true,sensitivity:"base"});if(r.major!==e.major)return r.major<e.major?-1:1;if(r.minor!==e.minor)return r.minor<e.minor?-1:1;if(r.patch!==e.patch)return r.patch<e.patch?-1:1;if(r.pre.length===0&&e.pre.length===0)return 0;if(r.pre.length===0)return 1;if(e.pre.length===0)return -1;const o=Math.max(r.pre.length,e.pre.length);for(let i=0;i<o;i++){const u=r.pre[i],a=e.pre[i];if(u===void 0)return -1;if(a===void 0)return 1;const m=h(u,a);if(m!==0)return m}return 0}async function P(){try{const{data:n}=await get(`https://registry.npmjs.org/${name}/latest`);if(b(n.version,version)<=0)return;note(`Current: ${bold(version)} \u2192 Latest: ${bold(n.version)}
2
- Run: ${getPackageManager()} i -g ${name}`,"Update available");}catch{}}export{P as checkForUpdate};
1
+ import'./chunk-A7RKGLUR.mjs';import {getPackageManager}from'./getPackageManager';import {name,version}from'../package.json';import {spinner,note}from'@clack/prompts';import {bold}from'colorette';import {get}from'./fetch';function f(n){const r=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(n);return r?{major:Number(r[1]),minor:Number(r[2]),patch:Number(r[3]),pre:r[4]?r[4].split("."):[]}:null}function b(n,r){const e=/^\d+$/.test(n),t=/^\d+$/.test(r);if(e&&t){const o=Number(n),i=Number(r);return o<i?-1:o>i?1:0}return e&&!t?-1:!e&&t?1:n<r?-1:n>r?1:0}function v(n,r){const e=f(n),t=f(r);if(!e||!t)return n.localeCompare(r,void 0,{numeric:true,sensitivity:"base"});if(e.major!==t.major)return e.major<t.major?-1:1;if(e.minor!==t.minor)return e.minor<t.minor?-1:1;if(e.patch!==t.patch)return e.patch<t.patch?-1:1;if(e.pre.length===0&&t.pre.length===0)return 0;if(e.pre.length===0)return 1;if(t.pre.length===0)return -1;const o=Math.max(e.pre.length,t.pre.length);for(let i=0;i<o;i++){const a=e.pre[i],u=t.pre[i];if(a===void 0)return -1;if(u===void 0)return 1;const m=b(a,u);if(m!==0)return m}return 0}async function k(){const n=spinner();n.start("Checking for updates");try{const{data:r}=await get(`https://registry.npmjs.org/${name}/latest`);if(v(r.version,version)<=0)return;note(`Current: ${bold(version)} \u2192 Latest: ${bold(r.version)}
2
+ Run: ${getPackageManager()} i -g ${name}`,"Update available");}catch{}finally{n.clear();}}export{k as checkForUpdate,b as compareIdentifier,v as compareSemver,f as parseSemver};
package/out/clone.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- declare function clone(name: string, type: string, template: string, force: boolean): Promise<void>;
1
+ declare function clone(name: string, template: string, force: boolean): Promise<void>;
2
2
 
3
3
  export { clone };
package/out/clone.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare function clone(name: string, type: string, template: string, force: boolean): Promise<void>;
1
+ declare function clone(name: string, template: string, force: boolean): Promise<void>;
2
2
 
3
3
  export { clone };
package/out/clone.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var prompts=require('@clack/prompts'),s=require('degit');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var s__default=/*#__PURE__*/_interopDefault(s);async function a(e,o,n,r){const t=prompts.spinner();t.start("Cloning repository"),await s__default.default(`xcfio/template/${o}/${n}`,{force:r,cache:true,verbose:true}).clone(e),t.stop("Template cloned successfully");}exports.clone=a;
1
+ 'use strict';var prompts=require('@clack/prompts'),i=require('degit');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var i__default=/*#__PURE__*/_interopDefault(i);async function p(t,o,n){const e=prompts.spinner();e.start("Cloning repository"),await i__default.default(`xcfio/template/${o}`,{force:n,cache:true,verbose:true}).clone(t),e.stop("Template cloned successfully");}exports.clone=p;
package/out/clone.mjs CHANGED
@@ -1 +1 @@
1
- import'./chunk-A7RKGLUR.mjs';import {spinner}from'@clack/prompts';import s from'degit';async function a(e,o,n,r){const t=spinner();t.start("Cloning repository"),await s(`xcfio/template/${o}/${n}`,{force:r,cache:true,verbose:true}).clone(e),t.stop("Template cloned successfully");}export{a as clone};
1
+ import'./chunk-A7RKGLUR.mjs';import {spinner}from'@clack/prompts';import i from'degit';async function p(t,o,n){const e=spinner();e.start("Cloning repository"),await i(`xcfio/template/${o}`,{force:n,cache:true,verbose:true}).clone(t),e.stop("Template cloned successfully");}export{p as clone};
@@ -1,3 +1,4 @@
1
+ declare let packageManager: "npm" | "yarn" | "pnpm";
1
2
  declare function getPackageManager(): "npm" | "yarn" | "pnpm";
2
3
 
3
- export { getPackageManager };
4
+ export { getPackageManager, packageManager };
@@ -1,3 +1,4 @@
1
+ declare let packageManager: "npm" | "yarn" | "pnpm";
1
2
  declare function getPackageManager(): "npm" | "yarn" | "pnpm";
2
3
 
3
- export { getPackageManager };
4
+ export { getPackageManager, packageManager };
@@ -1 +1 @@
1
- 'use strict';var node_child_process=require('node:child_process');let n;function p(){if(n)return n;try{return node_child_process.execSync("pnpm --version",{stdio:"ignore"}),n="pnpm","pnpm"}catch{}try{return node_child_process.execSync("yarn --version",{stdio:"ignore"}),n="yarn","yarn"}catch{}return n="npm","npm"}exports.getPackageManager=p;
1
+ 'use strict';var node_child_process=require('node:child_process');exports.packageManager=void 0;function p(){if(exports.packageManager)return exports.packageManager;try{return node_child_process.execSync("pnpm --version",{stdio:"ignore"}),exports.packageManager="pnpm","pnpm"}catch{}try{return node_child_process.execSync("yarn --version",{stdio:"ignore"}),exports.packageManager="yarn","yarn"}catch{}return exports.packageManager="npm","npm"}exports.getPackageManager=p;
@@ -1 +1 @@
1
- import'./chunk-A7RKGLUR.mjs';import {execSync}from'node:child_process';let n;function p(){if(n)return n;try{return execSync("pnpm --version",{stdio:"ignore"}),n="pnpm","pnpm"}catch{}try{return execSync("yarn --version",{stdio:"ignore"}),n="yarn","yarn"}catch{}return n="npm","npm"}export{p as getPackageManager};
1
+ import'./chunk-A7RKGLUR.mjs';import {execSync}from'node:child_process';let n;function p(){if(n)return n;try{return execSync("pnpm --version",{stdio:"ignore"}),n="pnpm","pnpm"}catch{}try{return execSync("yarn --version",{stdio:"ignore"}),n="yarn","yarn"}catch{}return n="npm","npm"}export{p as getPackageManager,n as packageManager};
package/out/index.d.mts CHANGED
@@ -1,11 +1,14 @@
1
- export { checkForUpdate } from './checkForUpdate.mjs';
1
+ export { checkForUpdate, compareIdentifier, compareSemver, parseSemver } from './checkForUpdate.mjs';
2
2
  export { clone } from './clone.mjs';
3
3
  export { get } from './fetch.mjs';
4
4
  export { IgnoredDirectory, getCategories } from './getCategories.mjs';
5
- export { getPackageManager } from './getPackageManager.mjs';
5
+ export { getPackageManager, packageManager } from './getPackageManager.mjs';
6
6
  export { getTemplates } from './getTemplates.mjs';
7
+ export { isInvalidPath } from './isInvalidPath.mjs';
8
+ export { isValidDirectoryName } from './isValidDirectoryName.mjs';
7
9
  export { main } from './main.mjs';
8
- export { FilteredGithubResponse, GithubAPIResponse } from './type.mjs';
10
+ export { showHelp } from './showHelp.mjs';
11
+ export { FilteredGithubResponse, GithubAPIResponse, ParsedSemver } from './type.mjs';
9
12
 
10
13
  var version = "0.0.4";
11
14
 
package/out/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
- export { checkForUpdate } from './checkForUpdate.js';
1
+ export { checkForUpdate, compareIdentifier, compareSemver, parseSemver } from './checkForUpdate.js';
2
2
  export { clone } from './clone.js';
3
3
  export { get } from './fetch.js';
4
4
  export { IgnoredDirectory, getCategories } from './getCategories.js';
5
- export { getPackageManager } from './getPackageManager.js';
5
+ export { getPackageManager, packageManager } from './getPackageManager.js';
6
6
  export { getTemplates } from './getTemplates.js';
7
+ export { isInvalidPath } from './isInvalidPath.js';
8
+ export { isValidDirectoryName } from './isValidDirectoryName.js';
7
9
  export { main } from './main.js';
8
- export { FilteredGithubResponse, GithubAPIResponse } from './type.js';
10
+ export { showHelp } from './showHelp.js';
11
+ export { FilteredGithubResponse, GithubAPIResponse, ParsedSemver } from './type.js';
9
12
 
10
13
  var version = "0.0.4";
11
14
 
package/out/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var package_json=require('../package.json'),checkForUpdate=require('./checkForUpdate'),clone=require('./clone'),fetch=require('./fetch'),getCategories=require('./getCategories'),getPackageManager=require('./getPackageManager'),getTemplates=require('./getTemplates'),main=require('./main'),type=require('./type');Object.defineProperty(exports,"version",{enumerable:true,get:function(){return package_json.version}});Object.keys(checkForUpdate).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return checkForUpdate[k]}})});Object.keys(clone).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return clone[k]}})});Object.keys(fetch).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return fetch[k]}})});Object.keys(getCategories).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getCategories[k]}})});Object.keys(getPackageManager).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getPackageManager[k]}})});Object.keys(getTemplates).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getTemplates[k]}})});Object.keys(main).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return main[k]}})});Object.keys(type).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return type[k]}})});
1
+ 'use strict';var package_json=require('../package.json'),checkForUpdate=require('./checkForUpdate'),clone=require('./clone'),fetch=require('./fetch'),getCategories=require('./getCategories'),getPackageManager=require('./getPackageManager'),getTemplates=require('./getTemplates'),isInvalidPath=require('./isInvalidPath'),isValidDirectoryName=require('./isValidDirectoryName'),main=require('./main'),showHelp=require('./showHelp'),type=require('./type');Object.defineProperty(exports,"version",{enumerable:true,get:function(){return package_json.version}});Object.keys(checkForUpdate).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return checkForUpdate[k]}})});Object.keys(clone).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return clone[k]}})});Object.keys(fetch).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return fetch[k]}})});Object.keys(getCategories).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getCategories[k]}})});Object.keys(getPackageManager).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getPackageManager[k]}})});Object.keys(getTemplates).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getTemplates[k]}})});Object.keys(isInvalidPath).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return isInvalidPath[k]}})});Object.keys(isValidDirectoryName).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return isValidDirectoryName[k]}})});Object.keys(main).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return main[k]}})});Object.keys(showHelp).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return showHelp[k]}})});Object.keys(type).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return type[k]}})});
package/out/index.mjs CHANGED
@@ -1 +1 @@
1
- import'./chunk-A7RKGLUR.mjs';export{version}from'../package.json';export*from'./checkForUpdate';export*from'./clone';export*from'./fetch';export*from'./getCategories';export*from'./getPackageManager';export*from'./getTemplates';export*from'./main';export*from'./type';
1
+ import'./chunk-A7RKGLUR.mjs';export{version}from'../package.json';export*from'./checkForUpdate';export*from'./clone';export*from'./fetch';export*from'./getCategories';export*from'./getPackageManager';export*from'./getTemplates';export*from'./isInvalidPath';export*from'./isValidDirectoryName';export*from'./main';export*from'./showHelp';export*from'./type';
@@ -0,0 +1,3 @@
1
+ declare function isValidDirectoryName(name: string): boolean | string;
2
+
3
+ export { isValidDirectoryName };
@@ -0,0 +1,3 @@
1
+ declare function isValidDirectoryName(name: string): boolean | string;
2
+
3
+ export { isValidDirectoryName };
@@ -0,0 +1 @@
1
+ 'use strict';function t(r){return !r||!r.trim()?"Directory name cannot be empty":r.length>255?"Directory name is too long":/[<>:"/\\|?*\x00-\x1f]/.test(r)?"Directory name contains invalid characters":/^[. ]|[. ]$/.test(r)?"Directory name cannot start or end with a dot or space":/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i.test(r)?"Directory name is a reserved name":true}exports.isValidDirectoryName=t;
@@ -0,0 +1 @@
1
+ import'./chunk-A7RKGLUR.mjs';function t(r){return !r||!r.trim()?"Directory name cannot be empty":r.length>255?"Directory name is too long":/[<>:"/\\|?*\x00-\x1f]/.test(r)?"Directory name contains invalid characters":/^[. ]|[. ]$/.test(r)?"Directory name cannot start or end with a dot or space":/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i.test(r)?"Directory name is a reserved name":true}export{t as isValidDirectoryName};
package/out/main.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var prompts=require('@clack/prompts'),getPackageManager=require('./getPackageManager'),colorette=require('colorette'),checkForUpdate=require('./checkForUpdate'),isInvalidPath=require('./isInvalidPath'),getCategories=require('./getCategories'),getTemplates=require('./getTemplates'),clone=require('./clone'),node_path=require('node:path');async function q(){prompts.intro(colorette.blue("Create a new project"));const c=prompts.spinner();c.start("Checking for updates"),await checkForUpdate.checkForUpdate(),c.clear();const t=await prompts.text({message:"Project Name",placeholder:"my-project",defaultValue:"my-project"});if(prompts.isCancel(t))return prompts.cancel("Operation cancelled"),process.exit(0);const s=isInvalidPath.isInvalidPath(node_path.join(process.cwd(),t));let m=false;if(s!==null)if(s){const e=await prompts.confirm({message:`Directory ${colorette.green(t)} already exists. Do you want to overwrite it?`});if(prompts.isCancel(e)||!e)return prompts.cancel("Operation cancelled"),process.exit(0);m=true;}else return prompts.cancel(`${colorette.green(t)} is a file. Please choose a different project name.`),process.exit(1);const d=await getCategories.getCategories(),r=await prompts.select({message:"Select a category",options:d.map(e=>({name:e.name,value:e.name}))});if(prompts.isCancel(r))return prompts.cancel("Operation cancelled"),process.exit(0);const g=await getTemplates.getTemplates(r),n=await prompts.select({message:"Select a template",options:g.map(e=>({name:e.name,value:e.name}))});if(prompts.isCancel(n))return prompts.cancel("Operation cancelled"),process.exit(0);const l=await prompts.confirm({message:`Create project with name: ${colorette.bold(t)}, category: ${colorette.bold(r)}, template: ${colorette.bold(n)}?`});if(prompts.isCancel(l)||!l)return prompts.cancel("Operation cancelled"),process.exit(0);await clone.clone(t,r,n,m),prompts.note(`cd ${t}
1
+ 'use strict';var prompts=require('@clack/prompts'),isValidDirectoryName=require('./isValidDirectoryName'),getPackageManager=require('./getPackageManager'),colorette=require('colorette'),checkForUpdate=require('./checkForUpdate'),isInvalidPath=require('./isInvalidPath'),getCategories=require('./getCategories'),getTemplates=require('./getTemplates'),node_util=require('node:util'),clone=require('./clone'),node_path=require('node:path');async function B(){prompts.intro(colorette.blue("cnpx - Create a new project from a template"));const r=["",""],{values:t}=node_util.parseArgs({args:process.argv.slice(2),strict:false,options:{category:{type:"string",short:"c"},template:{type:"string",short:"t"},name:{type:"string",short:"n"},force:{type:"boolean",short:"f"},help:{type:"boolean",short:"h"}}});if(typeof t.name=="string"){const e=isValidDirectoryName.isValidDirectoryName(t.name);if(typeof e=="string")return prompts.cancel(e),process.exit(1)}if(typeof t.category=="string"&&(r[0]=t.category),typeof t.template=="string")if(t.template.includes("/")){const[e,n]=t.template.split("/");r[0]=e,r[1]=n;}else r[1]=t.template;await checkForUpdate.checkForUpdate();const o=typeof t.name=="string"?t.name:await prompts.text({message:"Project Name",placeholder:"my-project",defaultValue:"my-project",validate:e=>{if(!e)return;const n=isValidDirectoryName.isValidDirectoryName(e);if(typeof n=="string")return new Error(n)}});if(prompts.isCancel(o))return prompts.cancel("Operation cancelled"),process.exit(0);const p=isInvalidPath.isInvalidPath(node_path.join(process.cwd(),o));let l=typeof t.force=="boolean"?t.force:false;if(p!==null)if(p){if(t.force!==true){const e=await prompts.confirm({message:`Directory ${colorette.green(o)} already exists. Do you want to overwrite it?`});if(prompts.isCancel(e)||!e)return prompts.cancel("Operation cancelled"),process.exit(0)}l=true;}else return prompts.cancel(`${colorette.green(o)} is a file. Please choose a different project name.`),process.exit(1);const d=await getCategories.getCategories(),s=r[0]||await prompts.select({message:"Select a category",options:d.map(e=>({name:e.name,value:e.name}))});if(prompts.isCancel(s))return prompts.cancel("Operation cancelled"),process.exit(0);r[0]=s;const w=await getTemplates.getTemplates(s),m=r[1]||await prompts.select({message:"Select a template",options:w.map(e=>({name:e.name,value:e.name}))});if(prompts.isCancel(m))return prompts.cancel("Operation cancelled"),process.exit(0);if(r[1]=m,t.force!==true){const e=await prompts.confirm({message:`Create project with name: ${colorette.bold(o)}, category: ${colorette.bold(r[0])}, template: ${colorette.bold(r[1])}?`});if(prompts.isCancel(e)||!e)return prompts.cancel("Operation cancelled"),process.exit(0)}await clone.clone(o,`${r.join("/")}`,l),prompts.note(`cd ${o}
2
2
  ${getPackageManager.getPackageManager()} install
3
- node --run dev`,"To get started, run:"),prompts.outro(`Thanks for using template! \u2B50 Give a ${colorette.yellow("star")} on GitHub: https://github.com/xcfio/template`);}
4
- exports.main=q;
3
+ node --run dev`,"To get started, run:"),prompts.outro(`Thanks for using cnpx! \u2B50 Give a ${colorette.yellow("star")} on GitHub: https://github.com/xcfio/template`);}
4
+ exports.main=B;
package/out/main.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import'./chunk-A7RKGLUR.mjs';import {intro,spinner,text,isCancel,cancel,confirm,select,note,outro}from'@clack/prompts';import {getPackageManager}from'./getPackageManager';import {blue,green,bold,yellow}from'colorette';import {checkForUpdate}from'./checkForUpdate';import {isInvalidPath}from'./isInvalidPath';import {getCategories}from'./getCategories';import {getTemplates}from'./getTemplates';import {clone}from'./clone';import {join}from'node:path';async function q(){intro(blue("Create a new project"));const c=spinner();c.start("Checking for updates"),await checkForUpdate(),c.clear();const t=await text({message:"Project Name",placeholder:"my-project",defaultValue:"my-project"});if(isCancel(t))return cancel("Operation cancelled"),process.exit(0);const s=isInvalidPath(join(process.cwd(),t));let m=false;if(s!==null)if(s){const e=await confirm({message:`Directory ${green(t)} already exists. Do you want to overwrite it?`});if(isCancel(e)||!e)return cancel("Operation cancelled"),process.exit(0);m=true;}else return cancel(`${green(t)} is a file. Please choose a different project name.`),process.exit(1);const d=await getCategories(),r=await select({message:"Select a category",options:d.map(e=>({name:e.name,value:e.name}))});if(isCancel(r))return cancel("Operation cancelled"),process.exit(0);const g=await getTemplates(r),n=await select({message:"Select a template",options:g.map(e=>({name:e.name,value:e.name}))});if(isCancel(n))return cancel("Operation cancelled"),process.exit(0);const l=await confirm({message:`Create project with name: ${bold(t)}, category: ${bold(r)}, template: ${bold(n)}?`});if(isCancel(l)||!l)return cancel("Operation cancelled"),process.exit(0);await clone(t,r,n,m),note(`cd ${t}
1
+ import'./chunk-A7RKGLUR.mjs';import {intro,cancel,text,isCancel,confirm,select,note,outro}from'@clack/prompts';import {isValidDirectoryName}from'./isValidDirectoryName';import {getPackageManager}from'./getPackageManager';import {blue,green,bold,yellow}from'colorette';import {checkForUpdate}from'./checkForUpdate';import {isInvalidPath}from'./isInvalidPath';import {getCategories}from'./getCategories';import {getTemplates}from'./getTemplates';import {parseArgs}from'node:util';import {clone}from'./clone';import {join}from'node:path';async function B(){intro(blue("cnpx - Create a new project from a template"));const r=["",""],{values:t}=parseArgs({args:process.argv.slice(2),strict:false,options:{category:{type:"string",short:"c"},template:{type:"string",short:"t"},name:{type:"string",short:"n"},force:{type:"boolean",short:"f"},help:{type:"boolean",short:"h"}}});if(typeof t.name=="string"){const e=isValidDirectoryName(t.name);if(typeof e=="string")return cancel(e),process.exit(1)}if(typeof t.category=="string"&&(r[0]=t.category),typeof t.template=="string")if(t.template.includes("/")){const[e,n]=t.template.split("/");r[0]=e,r[1]=n;}else r[1]=t.template;await checkForUpdate();const o=typeof t.name=="string"?t.name:await text({message:"Project Name",placeholder:"my-project",defaultValue:"my-project",validate:e=>{if(!e)return;const n=isValidDirectoryName(e);if(typeof n=="string")return new Error(n)}});if(isCancel(o))return cancel("Operation cancelled"),process.exit(0);const p=isInvalidPath(join(process.cwd(),o));let l=typeof t.force=="boolean"?t.force:false;if(p!==null)if(p){if(t.force!==true){const e=await confirm({message:`Directory ${green(o)} already exists. Do you want to overwrite it?`});if(isCancel(e)||!e)return cancel("Operation cancelled"),process.exit(0)}l=true;}else return cancel(`${green(o)} is a file. Please choose a different project name.`),process.exit(1);const d=await getCategories(),s=r[0]||await select({message:"Select a category",options:d.map(e=>({name:e.name,value:e.name}))});if(isCancel(s))return cancel("Operation cancelled"),process.exit(0);r[0]=s;const w=await getTemplates(s),m=r[1]||await select({message:"Select a template",options:w.map(e=>({name:e.name,value:e.name}))});if(isCancel(m))return cancel("Operation cancelled"),process.exit(0);if(r[1]=m,t.force!==true){const e=await confirm({message:`Create project with name: ${bold(o)}, category: ${bold(r[0])}, template: ${bold(r[1])}?`});if(isCancel(e)||!e)return cancel("Operation cancelled"),process.exit(0)}await clone(o,`${r.join("/")}`,l),note(`cd ${o}
2
2
  ${getPackageManager()} install
3
- node --run dev`,"To get started, run:"),outro(`Thanks for using template! \u2B50 Give a ${yellow("star")} on GitHub: https://github.com/xcfio/template`);}
4
- export{q as main};
3
+ node --run dev`,"To get started, run:"),outro(`Thanks for using cnpx! \u2B50 Give a ${yellow("star")} on GitHub: https://github.com/xcfio/template`);}
4
+ export{B as main};
@@ -0,0 +1,3 @@
1
+ declare function showHelp(): never;
2
+
3
+ export { showHelp };
@@ -0,0 +1,3 @@
1
+ declare function showHelp(): never;
2
+
3
+ export { showHelp };
@@ -0,0 +1,10 @@
1
+ 'use strict';var colorette=require('colorette');function p(){console.log(`
2
+ ${colorette.blue(colorette.bold("cnpx"))} - Create a new project from a template
3
+
4
+ ${colorette.bold("Options:")}
5
+ ${colorette.green("-n, --name")} ${colorette.dim("Project name")}
6
+ ${colorette.green("-c, --category")} ${colorette.dim("Template category")}
7
+ ${colorette.green("-t, --template")} ${colorette.dim("Template name")}
8
+ ${colorette.green("-f, --force")} ${colorette.dim("Overwrite existing directory")}
9
+ ${colorette.green("-h, --help")} ${colorette.dim("Show help")}
10
+ `),process.exit(0);}exports.showHelp=p;
@@ -0,0 +1,10 @@
1
+ import'./chunk-A7RKGLUR.mjs';import {blue,bold,green,dim}from'colorette';function p(){console.log(`
2
+ ${blue(bold("cnpx"))} - Create a new project from a template
3
+
4
+ ${bold("Options:")}
5
+ ${green("-n, --name")} ${dim("Project name")}
6
+ ${green("-c, --category")} ${dim("Template category")}
7
+ ${green("-t, --template")} ${dim("Template name")}
8
+ ${green("-f, --force")} ${dim("Overwrite existing directory")}
9
+ ${green("-h, --help")} ${dim("Show help")}
10
+ `),process.exit(0);}export{p as showHelp};
package/out/type.d.mts CHANGED
@@ -1,3 +1,9 @@
1
+ type ParsedSemver = {
2
+ major: number;
3
+ minor: number;
4
+ patch: number;
5
+ pre: string[];
6
+ };
1
7
  type FilteredGithubResponse = Array<{
2
8
  name: string;
3
9
  url: string;
@@ -21,4 +27,4 @@ type GithubAPIResponse = {
21
27
  };
22
28
  }>;
23
29
 
24
- export type { FilteredGithubResponse, GithubAPIResponse };
30
+ export type { FilteredGithubResponse, GithubAPIResponse, ParsedSemver };
package/out/type.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ type ParsedSemver = {
2
+ major: number;
3
+ minor: number;
4
+ patch: number;
5
+ pre: string[];
6
+ };
1
7
  type FilteredGithubResponse = Array<{
2
8
  name: string;
3
9
  url: string;
@@ -21,4 +27,4 @@ type GithubAPIResponse = {
21
27
  };
22
28
  }>;
23
29
 
24
- export type { FilteredGithubResponse, GithubAPIResponse };
30
+ export type { FilteredGithubResponse, GithubAPIResponse, ParsedSemver };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cnpx/cnpx",
3
- "version": "0.0.4-dev.20260403235918",
4
- "description": "A simple CLI to scaffold projects from remote templates",
3
+ "version": "0.0.4-dev.20260404115856",
4
+ "description": "An interactive CLI tool for creating new projects from curated templates hosted on GitHub. Pick a category, pick a template, and get coding.",
5
5
  "author": "xcfio",
6
6
  "homepage": "https://github.com/xcfio/template/tree/main/cnpx/cnpx#readme",
7
7
  "type": "commonjs",
@@ -29,14 +29,13 @@
29
29
  "url": "https://github.com/xcfio/template/issues",
30
30
  "email": "omarfaruksxp@gmail.com"
31
31
  },
32
- "funding": {
33
- "type": "patreon",
34
- "url": "https://www.patreon.com/xcfio"
35
- },
36
32
  "publishConfig": {
37
33
  "access": "public",
38
34
  "tag": "latest"
39
35
  },
36
+ "engines": {
37
+ "node": ">=22.5"
38
+ },
40
39
  "dependencies": {
41
40
  "@clack/prompts": "^1.2.0",
42
41
  "colorette": "^2.0.20",
@@ -48,10 +47,10 @@
48
47
  "tsup": "^8.5.1"
49
48
  },
50
49
  "scripts": {
51
- "fmt": "prettier --config=.prettierrc --write src",
52
50
  "lint": "prettier --config=.prettierrc --check src",
53
- "build": "tsup",
51
+ "fmt": "prettier --config=.prettierrc --write src",
52
+ "test": "tsc --noEmit",
54
53
  "dev": "tsup --watch",
55
- "test": "tsc --noEmit"
54
+ "build": "tsup"
56
55
  }
57
56
  }