@cnpx/cnpx 0.0.5-dev.20260405135545 → 0.0.6-dev.20260425010846

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
@@ -43,7 +43,7 @@ npm install -g @cnpx/cnpx
43
43
  yarn global add @cnpx/cnpx
44
44
  ```
45
45
 
46
- > **Requires Node.js 22.5 or later.** Check your version with `node --version`.
46
+ > **Requires Node.js 22.12 or later.** Check your version with `node --version`.
47
47
 
48
48
  Alternatively, run without installing:
49
49
 
@@ -66,7 +66,7 @@ cnpx
66
66
  Or skip straight to a known template with flags:
67
67
 
68
68
  ```bash
69
- cnpx --name my-app --template backend/fastify
69
+ cnpx --name=my-app --template=backend/fastify
70
70
  ```
71
71
 
72
72
  ---
@@ -82,7 +82,7 @@ All flags are optional. Any omitted value is collected interactively.
82
82
  | `--template` | `-t` | `string` | Template name. Accepts bare name (`fastify`) or `category/template` slash syntax. Slash syntax also sets `--category`. |
83
83
  | `--force` | `-f` | `boolean` | Overwrite a non-empty target directory without prompting. Skips both the overwrite confirmation and the final "create project?" confirmation. |
84
84
  | `--offline` | `-o` | `boolean` | Run in offline mode using locally cached templates. Requires `--template` in `category/template` format. |
85
- | `--help` | `-h` | `boolean` | Print the help message and exit. Also triggered by passing `help` as a bare argument. |
85
+ | `--help` | `-h` | `boolean` | Print the help message and exit. |
86
86
 
87
87
  ### Examples
88
88
 
@@ -91,26 +91,24 @@ All flags are optional. Any omitted value is collected interactively.
91
91
  cnpx
92
92
 
93
93
  # Name only — prompts for category and template
94
- cnpx --name my-project
94
+ cnpx --name=my-project
95
95
 
96
96
  # Slash syntax — sets both category and template
97
- cnpx -t backend/fastify
97
+ cnpx -t=backend/fastify
98
98
 
99
99
  # Category and template as separate flags
100
- cnpx --category backend --template fastify
100
+ cnpx --category=backend --template=fastify
101
101
 
102
102
  # All flags — no prompts at all
103
- cnpx -n my-app -t backend/fastify -f
103
+ cnpx -n=my-app -t=backend/fastify -f
104
104
 
105
105
  # Offline mode — uses cached templates, no network required
106
- cnpx --offline -n my-app -t backend/fastify
106
+ cnpx --offline -n=my-app -t=backend/fastify
107
107
 
108
108
  # Print help
109
109
  cnpx --help
110
110
  ```
111
111
 
112
- > **Note:** Unknown flags are silently ignored (`strict: false` parse mode). Only the flags listed above have any effect.
113
-
114
112
  ---
115
113
 
116
114
  ## Interactive Flow
@@ -212,7 +210,7 @@ At startup, cnpx fetches the latest version from the npm registry:
212
210
  GET https://registry.npmjs.org/@cnpx/cnpx/latest
213
211
  ```
214
212
 
215
- 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:
213
+ Versions are compared using the [`semver`](https://www.npmjs.com/package/semver) package. If the remote version is _newer_ than the running version, a note is displayed:
216
214
 
217
215
  ```
218
216
  ┌ Update available ───────────────╮
@@ -225,6 +223,8 @@ Versions are compared with a custom semver parser that handles pre-release ident
225
223
 
226
224
  The check is non-blocking — any error (network failure, rate limit) is silently swallowed so it never interrupts the main flow. In offline mode the update check is skipped entirely.
227
225
 
226
+ Registry responses are cached locally for 24 hours (via [`sqlite-cache`](https://www.npmjs.com/package/sqlite-cache)) so the check adds no latency on repeated runs.
227
+
228
228
  ---
229
229
 
230
230
  ## Validation
@@ -245,7 +245,7 @@ The project name is validated before any I/O happens. The following conditions c
245
245
 
246
246
  After name validation, the resolved path is checked:
247
247
 
248
- | Condition | Behaviour |
248
+ | Condition | Behavior |
249
249
  | -------------------------------- | ---------------------------------------------------------------- |
250
250
  | Path does not exist | Proceeds normally |
251
251
  | Path is an empty directory | Proceeds normally (no overwrite prompt) |
@@ -265,19 +265,23 @@ After name validation, the resolved path is checked:
265
265
 
266
266
  ### Runtime
267
267
 
268
- | Package | Version | Purpose |
269
- | ---------------- | --------- | ---------------------------------------------------------------------------------- |
270
- | `@clack/prompts` | `^1.2.0` | Beautiful interactive prompts — text, select, confirm, spinner, note, outro |
271
- | `colorette` | `^2.0.20` | Zero-dependency terminal colour helpers (`blue`, `green`, `bold`, `dim`, `yellow`) |
272
- | `degit` | `^2.8.4` | Fast git-based scaffolding without cloning full history; supports local caching |
268
+ | Package | Version | Purpose |
269
+ | ---------------- | --------- | ------------------------------------------------------------------------------- |
270
+ | `@clack/prompts` | `^1.2.0` | Beautiful interactive prompts — text, select, confirm, spinner, note, outro |
271
+ | `citty` | `^0.2.2` | CLI argument parsing and command definition |
272
+ | `colorette` | `^2.0.20` | Zero-dependency terminal color helpers (`blue`, `green`, `bold`, `gray`) |
273
+ | `degit` | `^2.8.4` | Fast git-based scaffolding without cloning full history; supports local caching |
274
+ | `semver` | `^7.7.4` | Reliable semver comparison for update checks |
275
+ | `sqlite-cache` | `^0.0.3` | TTL-aware persistent cache for network responses (stored in `~/.cnpx/`) |
273
276
 
274
277
  ### Dev / Build
275
278
 
276
- | Package | Version | Purpose |
277
- | -------------- | --------- | -------------------------------------------------------------------- |
278
- | `tsup` | `^8.5.1` | Zero-config TypeScript bundler; outputs CJS (`.js`) and ESM (`.mjs`) |
279
- | `@types/degit` | `^2.8.6` | TypeScript types for degit |
280
- | `@types/node` | `^25.5.2` | TypeScript types for Node.js built-in APIs |
279
+ | Package | Version | Purpose |
280
+ | --------------- | --------- | -------------------------------------------------------------------- |
281
+ | `tsup` | `^8.5.1` | Zero-config TypeScript bundler; outputs CJS (`.js`) and ESM (`.mjs`) |
282
+ | `@types/degit` | `^2.8.6` | TypeScript types for degit |
283
+ | `@types/node` | `^25.6.0` | TypeScript types for Node.js built-in APIs |
284
+ | `@types/semver` | `^7.7.1` | TypeScript types for semver |
281
285
 
282
286
  All runtime dependencies are pure-JS and work without native addons.
283
287
 
@@ -289,8 +293,9 @@ All runtime dependencies are pure-JS and work without native addons.
289
293
 
290
294
  ```
291
295
  src/
292
- ├── bin.ts # Entry point — wires showHelp + main
293
- ├── main.ts # Orchestrates the full interactive flow
296
+ ├── bin.ts # Entry point — bootstraps the CLI via citty
297
+ ├── main.ts # Defines and runs the main citty command
298
+ ├── cache.ts # SQLite-backed fetch cache (TTL: 24h, stored in ~/.cnpx/)
294
299
  ├── offlineRunner.ts # Offline mode flow (--offline flag)
295
300
  ├── clone.ts # Wraps degit clone with a spinner
296
301
  ├── confirmProject.ts # Extracted final confirmation prompt logic
@@ -302,8 +307,8 @@ src/
302
307
  ├── getPackageManager.ts # pnpm / yarn / npm detection (cached)
303
308
  ├── isInvalidPath.ts # Target path existence and type checks
304
309
  ├── isValidDirectoryName.ts # Name validation logic
305
- ├── fetch.ts # Thin fetch wrapper returning typed JSON
306
- └── showHelp.ts # --help output
310
+ ├── fetch.ts # Thin fetch wrapper with cache support
311
+ └── type.ts # Shared TypeScript types
307
312
  ```
308
313
 
309
314
  ### npm scripts
package/out/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
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;
2
+ 'use strict';require('./main');var r=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var s=r(()=>{process.removeAllListeners("warning");});var bin = s();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 {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};
2
+ import {a}from'./chunk-A7RKGLUR.mjs';import'./main';var n=a(()=>{process.removeAllListeners("warning");});var bin = n();export{bin as default};
@@ -0,0 +1,5 @@
1
+ import { SQLiteCache } from 'sqlite-cache';
2
+
3
+ declare const fetchCache: SQLiteCache<string, object>;
4
+
5
+ export { fetchCache };
package/out/cache.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { SQLiteCache } from 'sqlite-cache';
2
+
3
+ declare const fetchCache: SQLiteCache<string, object>;
4
+
5
+ export { fetchCache };
package/out/cache.js ADDED
@@ -0,0 +1 @@
1
+ 'use strict';var node_fs=require('node:fs'),sqliteCache=require('sqlite-cache'),node_os=require('node:os'),node_path=require('node:path');const r=node_path.join(node_os.homedir(),".cnpx");node_fs.existsSync(r)||node_fs.mkdirSync(r,{recursive:true});const p=new sqliteCache.SQLiteCache({path:node_path.join(r,"fetch-cache.db"),ttl:864e5,max:100});exports.fetchCache=p;
package/out/cache.mjs ADDED
@@ -0,0 +1 @@
1
+ import'./chunk-A7RKGLUR.mjs';import {existsSync,mkdirSync}from'node:fs';import {SQLiteCache}from'sqlite-cache';import {homedir}from'node:os';import {join}from'node:path';const r=join(homedir(),".cnpx");existsSync(r)||mkdirSync(r,{recursive:true});const p=new SQLiteCache({path:join(r,"fetch-cache.db"),ttl:864e5,max:100});export{p as fetchCache};
@@ -1,8 +1,3 @@
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;
6
1
  declare function checkForUpdate(): Promise<void>;
7
2
 
8
- export { checkForUpdate, compareIdentifier, compareSemver, parseSemver };
3
+ export { checkForUpdate };
@@ -1,8 +1,3 @@
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;
6
1
  declare function checkForUpdate(): Promise<void>;
7
2
 
8
- export { checkForUpdate, compareIdentifier, compareSemver, parseSemver };
3
+ export { checkForUpdate };
@@ -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 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 C(){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(n.clear(),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{n.isCancelled||n.clear();}}exports.checkForUpdate=C;exports.compareIdentifier=b;exports.compareSemver=v;exports.parseSemver=f;
1
+ 'use strict';var getPackageManager=require('./getPackageManager'),package_json=require('../package.json'),prompts=require('@clack/prompts'),colorette=require('colorette'),fetch=require('./fetch'),semver=require('semver');async function v(){const r=prompts.spinner();r.start("Checking for updates");try{const{data:t}=await fetch.get(`https://registry.npmjs.org/${package_json.name}/latest`);if(r.clear(),semver.lte(t.version,package_json.version))return;prompts.note(`Current: ${colorette.bold(package_json.version)} \u2192 Latest: ${colorette.bold(t.version)}
2
+ Run: ${getPackageManager.getPackageManager()} i -g ${package_json.name}`,"Update available");}catch{r.isCancelled||r.clear();}}exports.checkForUpdate=v;
@@ -1,2 +1,2 @@
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 C(){const n=spinner();n.start("Checking for updates");try{const{data:r}=await get(`https://registry.npmjs.org/${name}/latest`);if(n.clear(),v(r.version,version)<=0)return;note(`Current: ${bold(version)} \u2192 Latest: ${bold(r.version)}
2
- Run: ${getPackageManager()} i -g ${name}`,"Update available");}catch{n.isCancelled||n.clear();}}export{C as checkForUpdate,b as compareIdentifier,v as compareSemver,f as parseSemver};
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';import {lte}from'semver';async function v(){const r=spinner();r.start("Checking for updates");try{const{data:t}=await get(`https://registry.npmjs.org/${name}/latest`);if(r.clear(),lte(t.version,version))return;note(`Current: ${bold(version)} \u2192 Latest: ${bold(t.version)}
2
+ Run: ${getPackageManager()} i -g ${name}`,"Update available");}catch{r.isCancelled||r.clear();}}export{v as checkForUpdate};
package/out/fetch.js CHANGED
@@ -1 +1 @@
1
- 'use strict';async function n(a){const t=await fetch(a),e=await t.json();return {req:t,data:e}}exports.get=n;
1
+ 'use strict';var cache=require('./cache');async function o(e){if(cache.fetchCache.has(e))return {req:new Response,data:cache.fetchCache.get(e)};const t=await fetch(e),s=await t.json();return t.ok&&cache.fetchCache.set(e,s),{req:t,data:s}}exports.get=o;
package/out/fetch.mjs CHANGED
@@ -1 +1 @@
1
- import'./chunk-A7RKGLUR.mjs';async function n(a){const t=await fetch(a),e=await t.json();return {req:t,data:e}}export{n as get};
1
+ import'./chunk-A7RKGLUR.mjs';import {fetchCache}from'./cache';async function o(e){if(fetchCache.has(e))return {req:new Response,data:fetchCache.get(e)};const t=await fetch(e),s=await t.json();return t.ok&&fetchCache.set(e,s),{req:t,data:s}}export{o as get};
package/out/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- export { checkForUpdate, compareIdentifier, compareSemver, parseSemver } from './checkForUpdate.mjs';
1
+ export { fetchCache } from './cache.mjs';
2
+ export { checkForUpdate } from './checkForUpdate.mjs';
2
3
  export { clone } from './clone.mjs';
3
4
  export { confirmProject } from './confirmProject.mjs';
4
5
  export { get } from './fetch.mjs';
@@ -8,12 +9,12 @@ export { getProjectName } from './getProjectName.mjs';
8
9
  export { getTemplates } from './getTemplates.mjs';
9
10
  export { isInvalidPath } from './isInvalidPath.mjs';
10
11
  export { isValidDirectoryName } from './isValidDirectoryName.mjs';
11
- export { main } from './main.mjs';
12
12
  export { offlineRunner } from './offlineRunner.mjs';
13
13
  export { parseTemplate } from './parseTemplate.mjs';
14
14
  export { showHelp } from './showHelp.mjs';
15
- export { FilteredGithubResponse, GithubAPIResponse, ParsedSemver } from './type.mjs';
15
+ export { FilteredGithubResponse, GithubAPIResponse } from './type.mjs';
16
+ import 'sqlite-cache';
16
17
 
17
- var version = "0.0.5";
18
+ var version = "0.0.6";
18
19
 
19
20
  export { version };
package/out/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { checkForUpdate, compareIdentifier, compareSemver, parseSemver } from './checkForUpdate.js';
1
+ export { fetchCache } from './cache.js';
2
+ export { checkForUpdate } from './checkForUpdate.js';
2
3
  export { clone } from './clone.js';
3
4
  export { confirmProject } from './confirmProject.js';
4
5
  export { get } from './fetch.js';
@@ -8,12 +9,12 @@ export { getProjectName } from './getProjectName.js';
8
9
  export { getTemplates } from './getTemplates.js';
9
10
  export { isInvalidPath } from './isInvalidPath.js';
10
11
  export { isValidDirectoryName } from './isValidDirectoryName.js';
11
- export { main } from './main.js';
12
12
  export { offlineRunner } from './offlineRunner.js';
13
13
  export { parseTemplate } from './parseTemplate.js';
14
14
  export { showHelp } from './showHelp.js';
15
- export { FilteredGithubResponse, GithubAPIResponse, ParsedSemver } from './type.js';
15
+ export { FilteredGithubResponse, GithubAPIResponse } from './type.js';
16
+ import 'sqlite-cache';
16
17
 
17
- var version = "0.0.5";
18
+ var version = "0.0.6";
18
19
 
19
20
  export { version };
package/out/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var package_json=require('../package.json'),checkForUpdate=require('./checkForUpdate'),clone=require('./clone'),confirmProject=require('./confirmProject'),fetch=require('./fetch'),getCategories=require('./getCategories'),getPackageManager=require('./getPackageManager'),getProjectName=require('./getProjectName'),getTemplates=require('./getTemplates'),isInvalidPath=require('./isInvalidPath'),isValidDirectoryName=require('./isValidDirectoryName'),main=require('./main'),offlineRunner=require('./offlineRunner'),parseTemplate=require('./parseTemplate'),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(confirmProject).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return confirmProject[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(getProjectName).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getProjectName[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(offlineRunner).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return offlineRunner[k]}})});Object.keys(parseTemplate).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return parseTemplate[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]}})});
1
+ 'use strict';var package_json=require('../package.json'),cache=require('./cache'),checkForUpdate=require('./checkForUpdate'),clone=require('./clone'),confirmProject=require('./confirmProject'),fetch=require('./fetch'),getCategories=require('./getCategories'),getPackageManager=require('./getPackageManager'),getProjectName=require('./getProjectName'),getTemplates=require('./getTemplates'),isInvalidPath=require('./isInvalidPath'),isValidDirectoryName=require('./isValidDirectoryName'),main=require('./main'),offlineRunner=require('./offlineRunner'),parseTemplate=require('./parseTemplate'),showHelp=require('./showHelp'),type=require('./type');Object.defineProperty(exports,"version",{enumerable:true,get:function(){return package_json.version}});Object.keys(cache).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return cache[k]}})});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(confirmProject).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return confirmProject[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(getProjectName).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return getProjectName[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(offlineRunner).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return offlineRunner[k]}})});Object.keys(parseTemplate).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return parseTemplate[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'./confirmProject';export*from'./fetch';export*from'./getCategories';export*from'./getPackageManager';export*from'./getProjectName';export*from'./getTemplates';export*from'./isInvalidPath';export*from'./isValidDirectoryName';export*from'./main';export*from'./offlineRunner';export*from'./parseTemplate';export*from'./showHelp';export*from'./type';
1
+ import'./chunk-A7RKGLUR.mjs';export{version}from'../package.json';export*from'./cache';export*from'./checkForUpdate';export*from'./clone';export*from'./confirmProject';export*from'./fetch';export*from'./getCategories';export*from'./getPackageManager';export*from'./getProjectName';export*from'./getTemplates';export*from'./isInvalidPath';export*from'./isValidDirectoryName';export*from'./main';export*from'./offlineRunner';export*from'./parseTemplate';export*from'./showHelp';export*from'./type';
package/out/main.d.mts CHANGED
@@ -1,3 +1,2 @@
1
- declare function main(): Promise<undefined>;
2
1
 
3
- export { main };
2
+ export { }
package/out/main.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- declare function main(): Promise<undefined>;
2
1
 
3
- export { main };
2
+ export { }
package/out/main.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var prompts=require('@clack/prompts'),getPackageManager=require('./getPackageManager'),confirmProject=require('./confirmProject'),getProjectName=require('./getProjectName'),checkForUpdate=require('./checkForUpdate'),getCategories=require('./getCategories'),isInvalidPath=require('./isInvalidPath'),parseTemplate=require('./parseTemplate'),offlineRunner=require('./offlineRunner'),getTemplates=require('./getTemplates'),colorette=require('colorette'),node_util=require('node:util'),clone=require('./clone'),node_path=require('node:path');async function Q(){prompts.intro(colorette.blue("cnpx - Create a new project from a template"));const{values:e}=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"},offline:{type:"boolean",short:"o"}}});if(e.offline===true)return await offlineRunner.offlineRunner({...e});const o=await getProjectName.getProjectName(e.name);if(!o)return process.exit(0);let r=parseTemplate.parseTemplate(e.category,e.template);await checkForUpdate.checkForUpdate();const n=isInvalidPath.isInvalidPath(node_path.join(process.cwd(),o));let c=typeof e.force=="boolean"?e.force:false;if(n!==null)if(n){if(e.force!==true){const t=await prompts.confirm({message:`Directory ${colorette.green(o)} already exists. Do you want to overwrite it?`});if(prompts.isCancel(t)||!t)return prompts.cancel("Operation cancelled"),process.exit(0)}}else return prompts.cancel(`${o} is a file. Please choose a different project name.`),process.exit(1);const l=await getCategories.getCategories(),i=r[0]||await prompts.select({message:"Select a category",options:l.map(t=>({name:t.name,value:t.name}))});if(prompts.isCancel(i))return prompts.cancel("Operation cancelled"),process.exit(0);r[0]=i;const f=await getTemplates.getTemplates(i),p=r[1]||await prompts.select({message:"Select a template",options:f.map(t=>({name:t.name,value:t.name}))});if(prompts.isCancel(p))return prompts.cancel("Operation cancelled"),process.exit(0);if(r[1]=p,!await confirmProject.confirmProject(o,r[0],r[1],c))return process.exit(0);await clone.clone(o,`${r.join("/")}`,c),prompts.note(`cd ${o}
1
+ 'use strict';var prompts=require('@clack/prompts'),getPackageManager=require('./getPackageManager'),confirmProject=require('./confirmProject'),getProjectName=require('./getProjectName'),checkForUpdate=require('./checkForUpdate'),getCategories=require('./getCategories'),isInvalidPath=require('./isInvalidPath'),parseTemplate=require('./parseTemplate'),offlineRunner=require('./offlineRunner'),getTemplates=require('./getTemplates'),citty=require('citty'),colorette=require('colorette'),clone=require('./clone'),node_path=require('node:path');var d=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var F=d(()=>{const U=citty.defineCommand({meta:{name:"cnpx",description:"Create a new project from a template"},args:{category:{type:"string",alias:"c",description:"Template category"},template:{type:"string",alias:"t",description:"Template name"},name:{type:"string",alias:"n",description:"Project name"},force:{type:"boolean",alias:"f",description:"Overwrite existing directory"},offline:{type:"boolean",alias:"o",description:"Use offline mode"}},async run({args:t}){if(prompts.intro(colorette.blue("cnpx - Create a new project from a template")),t.offline)return await offlineRunner.offlineRunner({...t});const e=await getProjectName.getProjectName(t.name);if(!e)return process.exit(0);let r=parseTemplate.parseTemplate(t.category,t.template);await checkForUpdate.checkForUpdate();const s=isInvalidPath.isInvalidPath(node_path.join(process.cwd(),e));let c=typeof t.force=="boolean"?t.force:false;if(s!==null)if(s){if(!t.force){const o=await prompts.confirm({message:`Directory ${colorette.green(e)} already exists. Do you want to overwrite it?`});if(prompts.isCancel(o)||!o)return prompts.cancel("Operation cancelled"),process.exit(0)}}else return prompts.cancel(`${e} is a file. Please choose a different project name.`),process.exit(1);const l=await getCategories.getCategories(),i=r[0]||await prompts.select({message:"Select a category",options:l.map(o=>({name:o.name,value:o.name}))});if(prompts.isCancel(i))return prompts.cancel("Operation cancelled"),process.exit(0);r[0]=i;const f=await getTemplates.getTemplates(i),m=r[1]||await prompts.select({message:"Select a template",options:f.map(o=>({name:o.name,value:o.name}))});if(prompts.isCancel(m))return prompts.cancel("Operation cancelled"),process.exit(0);if(r[1]=m,!await confirmProject.confirmProject(e,r[0],r[1],c))return process.exit(0);await clone.clone(e,`${r.join("/")}`,c),prompts.note(`cd ${e}
2
2
  ${getPackageManager.getPackageManager()} install
3
- node --run dev`,"To get started, run:"),prompts.outro(`Thanks for using cnpx! If you have any issues or feedback, please open an issue at ${colorette.gray("https://github.com/xcfio/template/issues")}`);}
4
- exports.main=Q;
3
+ node --run dev`,"To get started, run:"),prompts.outro(`Thanks for using cnpx! If you have any issues or feedback, please open an issue at ${colorette.gray("https://github.com/xcfio/template/issues")}`);}});citty.runMain(U);});var main = F();
4
+ module.exports=main;
package/out/main.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import'./chunk-A7RKGLUR.mjs';import {intro,confirm,isCancel,cancel,select,note,outro}from'@clack/prompts';import {getPackageManager}from'./getPackageManager';import {confirmProject}from'./confirmProject';import {getProjectName}from'./getProjectName';import {checkForUpdate}from'./checkForUpdate';import {getCategories}from'./getCategories';import {isInvalidPath}from'./isInvalidPath';import {parseTemplate}from'./parseTemplate';import {offlineRunner}from'./offlineRunner';import {getTemplates}from'./getTemplates';import {blue,green,gray}from'colorette';import {parseArgs}from'node:util';import {clone}from'./clone';import {join}from'node:path';async function Q(){intro(blue("cnpx - Create a new project from a template"));const{values:e}=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"},offline:{type:"boolean",short:"o"}}});if(e.offline===true)return await offlineRunner({...e});const o=await getProjectName(e.name);if(!o)return process.exit(0);let r=parseTemplate(e.category,e.template);await checkForUpdate();const n=isInvalidPath(join(process.cwd(),o));let c=typeof e.force=="boolean"?e.force:false;if(n!==null)if(n){if(e.force!==true){const t=await confirm({message:`Directory ${green(o)} already exists. Do you want to overwrite it?`});if(isCancel(t)||!t)return cancel("Operation cancelled"),process.exit(0)}}else return cancel(`${o} is a file. Please choose a different project name.`),process.exit(1);const l=await getCategories(),i=r[0]||await select({message:"Select a category",options:l.map(t=>({name:t.name,value:t.name}))});if(isCancel(i))return cancel("Operation cancelled"),process.exit(0);r[0]=i;const f=await getTemplates(i),p=r[1]||await select({message:"Select a template",options:f.map(t=>({name:t.name,value:t.name}))});if(isCancel(p))return cancel("Operation cancelled"),process.exit(0);if(r[1]=p,!await confirmProject(o,r[0],r[1],c))return process.exit(0);await clone(o,`${r.join("/")}`,c),note(`cd ${o}
1
+ import {a}from'./chunk-A7RKGLUR.mjs';import {intro,confirm,isCancel,cancel,select,note,outro}from'@clack/prompts';import {getPackageManager}from'./getPackageManager';import {confirmProject}from'./confirmProject';import {getProjectName}from'./getProjectName';import {checkForUpdate}from'./checkForUpdate';import {getCategories}from'./getCategories';import {isInvalidPath}from'./isInvalidPath';import {parseTemplate}from'./parseTemplate';import {offlineRunner}from'./offlineRunner';import {getTemplates}from'./getTemplates';import {defineCommand,runMain}from'citty';import {blue,green,gray}from'colorette';import {clone}from'./clone';import {join}from'node:path';var F=a(()=>{const U=defineCommand({meta:{name:"cnpx",description:"Create a new project from a template"},args:{category:{type:"string",alias:"c",description:"Template category"},template:{type:"string",alias:"t",description:"Template name"},name:{type:"string",alias:"n",description:"Project name"},force:{type:"boolean",alias:"f",description:"Overwrite existing directory"},offline:{type:"boolean",alias:"o",description:"Use offline mode"}},async run({args:e}){if(intro(blue("cnpx - Create a new project from a template")),e.offline)return await offlineRunner({...e});const o=await getProjectName(e.name);if(!o)return process.exit(0);let r=parseTemplate(e.category,e.template);await checkForUpdate();const s=isInvalidPath(join(process.cwd(),o));let c=typeof e.force=="boolean"?e.force:false;if(s!==null)if(s){if(!e.force){const t=await confirm({message:`Directory ${green(o)} already exists. Do you want to overwrite it?`});if(isCancel(t)||!t)return cancel("Operation cancelled"),process.exit(0)}}else return cancel(`${o} is a file. Please choose a different project name.`),process.exit(1);const l=await getCategories(),i=r[0]||await select({message:"Select a category",options:l.map(t=>({name:t.name,value:t.name}))});if(isCancel(i))return cancel("Operation cancelled"),process.exit(0);r[0]=i;const f=await getTemplates(i),m=r[1]||await select({message:"Select a template",options:f.map(t=>({name:t.name,value:t.name}))});if(isCancel(m))return cancel("Operation cancelled"),process.exit(0);if(r[1]=m,!await confirmProject(o,r[0],r[1],c))return process.exit(0);await clone(o,`${r.join("/")}`,c),note(`cd ${o}
2
2
  ${getPackageManager()} install
3
- node --run dev`,"To get started, run:"),outro(`Thanks for using cnpx! If you have any issues or feedback, please open an issue at ${gray("https://github.com/xcfio/template/issues")}`);}
4
- export{Q as main};
3
+ node --run dev`,"To get started, run:"),outro(`Thanks for using cnpx! If you have any issues or feedback, please open an issue at ${gray("https://github.com/xcfio/template/issues")}`);}});runMain(U);});var main = F();
4
+ export{main as default};
package/out/type.d.mts CHANGED
@@ -1,9 +1,3 @@
1
- type ParsedSemver = {
2
- major: number;
3
- minor: number;
4
- patch: number;
5
- pre: string[];
6
- };
7
1
  type FilteredGithubResponse = Array<{
8
2
  name: string;
9
3
  url: string;
@@ -27,4 +21,4 @@ type GithubAPIResponse = {
27
21
  };
28
22
  }>;
29
23
 
30
- export type { FilteredGithubResponse, GithubAPIResponse, ParsedSemver };
24
+ export type { FilteredGithubResponse, GithubAPIResponse };
package/out/type.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- type ParsedSemver = {
2
- major: number;
3
- minor: number;
4
- patch: number;
5
- pre: string[];
6
- };
7
1
  type FilteredGithubResponse = Array<{
8
2
  name: string;
9
3
  url: string;
@@ -27,4 +21,4 @@ type GithubAPIResponse = {
27
21
  };
28
22
  }>;
29
23
 
30
- export type { FilteredGithubResponse, GithubAPIResponse, ParsedSemver };
24
+ export type { FilteredGithubResponse, GithubAPIResponse };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnpx/cnpx",
3
- "version": "0.0.5-dev.20260405135545",
3
+ "version": "0.0.6-dev.20260425010846",
4
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",
@@ -38,12 +38,16 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@clack/prompts": "^1.2.0",
41
+ "citty": "^0.2.2",
41
42
  "colorette": "^2.0.20",
42
- "degit": "^2.8.4"
43
+ "degit": "^2.8.4",
44
+ "semver": "^7.7.4",
45
+ "sqlite-cache": "^0.0.3"
43
46
  },
44
47
  "devDependencies": {
45
48
  "@types/degit": "^2.8.6",
46
- "@types/node": "^25.5.2",
49
+ "@types/node": "^25.6.0",
50
+ "@types/semver": "^7.7.1",
47
51
  "tsup": "^8.5.1"
48
52
  },
49
53
  "scripts": {