@locotineee/cli
v0.1.2
Published
CLI tool for adding NestJS modules from a registry (shadcn-style)
Downloads
278
Readme
@locotineee/cli
A shadcn-style CLI tool for adding pre-built NestJS modules to your project. Instead of installing opaque npm packages, this CLI copies module source code directly into your project — giving you full ownership and customization ability.
Table of Contents
- How It Works
- Quick Start
- Commands
- Configuration
- Registry Format
- Available Modules
- Self-Hosting a Registry
- Troubleshooting
How It Works
┌──────────┐ fetch ┌──────────────┐ copy ┌──────────────┐
│ CLI │ ──────────────>│ Registry │ ──────────────>│ Your Project│
│ (local) │ │ (remote) │ │ src/modules/│
└──────────┘ └──────────────┘ └──────────────┘
│
┌──────┴───────┐
│ Auto-wires │
│ app.module.ts│
│ package.json │
│ .env.example │
└──────────────┘- Fetch — The CLI downloads the module descriptor (
component.json) from a remote registry - Copy — Template files are fetched and written to your
src/modules/<name>/directory - Wire — The CLI auto-modifies
app.module.ts(via TypeScript AST),package.json, and.env.example
You own the code. Edit it however you want after installation.
Quick Start
# 1. Initialize the CLI config (one-time setup)
npx @locotineee/cli init
# 2. See what modules are available
npx @locotineee/cli list
# 3. Add a module to your project
npx @locotineee/cli add health
# 4. Install new dependencies that were added
npm installRunning from the monorepo (development)
If you're developing within this monorepo, you can run the CLI directly:
# From the project root
node packages/cli/dist/cli.js init
node packages/cli/dist/cli.js list
node packages/cli/dist/cli.js add healthCommands
init
Initializes the CLI configuration for your project. Creates a nestjs-cli.config.json file in your project root.
npx @locotineee/cli initWhat it does:
- Reads your
nest-cli.jsonto detect project structure - If monorepo, prompts you to select which app to target
- Prompts for a registry URL (defaults to the official registry)
- Writes
nestjs-cli.config.json
Monorepo detection:
The CLI reads nest-cli.json. If "monorepo": true, it lists all application projects and lets you pick one:
? Select target application:
❯ nestjs-ultimate (apps/nestjs-ultimate/src)
nestjs-starter (apps/nestjs-starter/src)Output file (nestjs-cli.config.json):
{
"registryUrl": "https://raw.githubusercontent.com/AggregatorIcapaci/nestjs-registry/main",
"modulesDir": "apps/nestjs-ultimate/src/modules",
"appModulePath": "apps/nestjs-ultimate/src/app.module.ts",
"targetApp": "nestjs-ultimate"
}list
Lists all available modules in the configured registry.
npx @locotineee/cli listExample output:
Available modules (registry v1.0.0)
Name Version Description
──────────────────────────────────────────
health 1.0.0 Health check endpoints using @nestjs/terminus [infrastructure, monitoring]
Total: 1 module(s)add
Adds a module from the registry into your project.
npx @locotineee/cli add <module-name>Example:
npx @locotineee/cli add healthWhat it does (step by step):
Loads config — Reads
nestjs-cli.config.json. If missing, tells you to runinitfirst.Validates module — Fetches
registry.jsonand confirms the module exists.Checks prerequisites — Some modules depend on others. For example,
healthrequiresDatabaseModuleto be present inapp.module.ts. If a prerequisite is missing, the CLI aborts with a clear message.Checks idempotency — If the module directory already exists, prompts whether to overwrite.
Shows installation plan — Displays what will be installed:
Adding module: health v1.0.0 ℹ Health check module with database, disk, and memory indicators Files: 5 Dependencies: @nestjs/terminus Env vars: HEALTH_DISK_THRESHOLD_PERCENT, HEALTH_MEMORY_HEAP_MB ? Proceed with installation? (Y/n)Copies files — Downloads and writes all module files:
✔ Created apps/nestjs-ultimate/src/modules/health/health.module.ts ✔ Created apps/nestjs-ultimate/src/modules/health/health.controller.ts ✔ Created apps/nestjs-ultimate/src/modules/health/indicators/database.indicator.ts ✔ Created apps/nestjs-ultimate/src/modules/health/indicators/disk.indicator.ts ✔ Created apps/nestjs-ultimate/src/modules/health/indicators/memory.indicator.tsAuto-wires
app.module.ts— Uses TypeScript AST manipulation (ts-morph) to safely:- Add
import { HealthModule } from '@modules/health/health.module'; - Insert
HealthModuleinto the@Module({ imports: [...] })array under the correct section comment
- Add
Updates
package.json— Adds any new dependencies:✔ Added dependency: @nestjs/terminus@^11.0.0Updates
.env.example— Appends new environment variables:# Disk usage threshold for health check (0-1) HEALTH_DISK_THRESHOLD_PERCENT=0.9 # Max heap memory in MB for health check HEALTH_MEMORY_HEAP_MB=300Prints post-install message:
✔ Module "health" added successfully! ℹ Run `npm install` to install @nestjs/terminus, then start your app.
After installation, remember to:
# Install any new dependencies that were added to package.json
npm install
# Start the app
npm run start:dev
# Test the health endpoint
curl http://localhost:3000/api/v1/healthConfiguration
nestjs-cli.config.json
Created by init. All fields:
| Field | Type | Description |
|-------|------|-------------|
| registryUrl | string | Base URL of the module registry |
| modulesDir | string | Where module files are copied to (relative to project root) |
| appModulePath | string | Path to app.module.ts for auto-wiring (relative to project root) |
| targetApp | string | Name of the target application (from nest-cli.json) |
You can edit this file manually. For example, to point to a different registry or change the modules directory.
Registry Format
The registry is a static file server (GitHub raw, S3, any CDN) with this structure:
registry/
registry.json # Master manifest
modules/
<module-name>/
component.json # Module descriptor
files/
<...template files...> # Actual source coderegistry.json (Master Manifest)
{
"version": "1.0.0",
"modules": [
{
"name": "health",
"description": "Health check endpoints using @nestjs/terminus",
"version": "1.0.0",
"tags": ["infrastructure", "monitoring"]
}
]
}component.json (Module Descriptor)
Each module has a component.json that describes everything the CLI needs:
{
"name": "health",
"description": "Health check module with database, disk, and memory indicators",
"version": "1.0.0",
"dependencies": {
"@nestjs/terminus": "^11.0.0"
},
"devDependencies": {},
"files": [
{ "source": "files/health.module.ts", "target": "health.module.ts" },
{ "source": "files/health.controller.ts", "target": "health.controller.ts" }
],
"moduleImport": {
"moduleName": "HealthModule",
"importPath": "@modules/health/health.module",
"section": "Feature Modules"
},
"envVars": [
{
"key": "HEALTH_DISK_THRESHOLD_PERCENT",
"value": "0.9",
"comment": "Disk usage threshold for health check (0-1)"
}
],
"requiredModules": ["DatabaseModule"],
"postInstallMessage": "Run `npm install` to install @nestjs/terminus, then start your app."
}Fields:
| Field | Description |
|-------|-------------|
| name | Module identifier (used in add <name>) |
| description | Human-readable description |
| version | Semantic version of this module template |
| dependencies | npm dependencies to add to package.json |
| devDependencies | npm devDependencies to add |
| files | Array of { source, target } — source is relative to module dir in registry, target is relative to destination dir |
| moduleImport.moduleName | The exported class name (e.g., HealthModule) |
| moduleImport.importPath | The import path to use in app.module.ts (uses project path aliases) |
| moduleImport.section | Which comment section in app.module.ts to insert under (e.g., "Feature Modules") |
| envVars | Environment variables to add to .env.example |
| requiredModules | Other modules that must be present in app.module.ts before this one can be added |
| postInstallMessage | Message displayed after successful installation |
Available Modules
health
Health check endpoints using @nestjs/terminus.
Adds:
| File | Description |
|------|-------------|
| health.module.ts | Module definition with Terminus |
| health.controller.ts | GET /health endpoint with Swagger docs |
| indicators/database.indicator.ts | Checks database connectivity via Prisma SELECT 1 |
| indicators/disk.indicator.ts | Checks disk usage against configurable threshold |
| indicators/memory.indicator.ts | Checks heap memory usage against configurable limit |
Dependencies: @nestjs/terminus@^11.0.0
Prerequisites: DatabaseModule (for the database health indicator)
Environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| HEALTH_DISK_THRESHOLD_PERCENT | 0.9 | Disk usage threshold (0-1, where 0.9 = 90%) |
| HEALTH_MEMORY_HEAP_MB | 300 | Maximum heap memory in MB |
Endpoint: GET /api/v1/health
Example response:
{
"status": "ok",
"info": {
"database": { "status": "up" },
"disk": { "status": "up", "usagePercent": 45, "threshold": 90 },
"memory": { "status": "up", "heapUsedMb": 85, "maxHeapMb": 300 }
}
}Self-Hosting a Registry
You can create your own private registry. The CLI only needs a static file server.
Option 1: GitHub Repository
- Create a repo with the registry structure above
- Push to GitHub
- Use the raw content URL:
https://raw.githubusercontent.com/<org>/<repo>/main
Option 2: Any Static Host (S3, Cloudflare R2, Nginx)
- Upload the registry files preserving the directory structure
- Ensure files are served with correct MIME types (
.jsonasapplication/json,.tsastext/plain) - Use the base URL when running
init
Creating a Custom Module
- Create
modules/<name>/component.jsonfollowing the schema above - Add your template files under
modules/<name>/files/ - Add the module entry to
registry.json - Template files are plain TypeScript — use the same path aliases as the target project (
@modules/*,@database/*,@config/*,@common/*)
Troubleshooting
"No nestjs-cli.config.json found"
Run npx @locotineee/cli init first to generate the config file.
"Required module X not found in app.module.ts"
The module you're trying to add has a prerequisite. Add the required module first. For example, health requires DatabaseModule.
"Failed to fetch registry"
Check that your registryUrl in nestjs-cli.config.json is correct and accessible. The CLI uses native fetch with a 10-second timeout.
Auto-wiring failed
If the CLI can't safely modify app.module.ts (unusual file structure, parse errors), it prints manual instructions:
⚠ Please add the following manually to app.module.ts:
import { HealthModule } from '@modules/health/health.module';
Then add HealthModule to the imports array in @Module().The module files are still copied — only the auto-wiring step is skipped.
Module directory already exists
The CLI detects existing modules and prompts before overwriting. Choose "No" to abort, or "Yes" to overwrite files (the auto-wiring step will skip if the import already exists in app.module.ts).
