npx-skills
v0.1.0
Published
CLI to install opencode AI agent skills
Readme
node-binary-package-template
A minimal, production-ready template for building Node.js CLI tools with TypeScript.
Clone this repo, rename a few fields, and you have a working npx my-command binary ready to publish to npm.
The included example command prints the caller's current working directory — the project where someone runs the command, not where your package is installed.
Table of contents
- Prerequisites
- Project structure
- Quick start
- Development workflow
- Testing locally
- Installing in another project
- Publishing to npm
- Customizing — renaming your command
- How
process.cwd()works - Scripts reference
Prerequisites
| Tool | Minimum version | |------|----------------| | Node.js | 18 | | npm | 7 |
Project structure
.
├── src/
│ └── index.ts # Your CLI source code (edit this)
├── dist/ # Compiled output — generated by the build, do not edit
├── tsup.config.ts # Bundler configuration
├── tsconfig.json # TypeScript configuration
├── package.json
├── .gitignore
├── .npmignore
└── README.md
dist/is gitignored and regenerated on every build. It is the only folder published to npm (controlled by thefilesfield inpackage.json).
Quick start
1. Clone the template
git clone https://github.com/your-username/node-binary-package-template.git my-new-cli
cd my-new-cli2. Remove the template's git history and start fresh
rm -rf .git
git init
git add .
git commit -m "Initial commit from template"3. Install dependencies
npm install4. Build and run
npm run build # compiles src/ → dist/
node dist/index.js # run it directlyYou should see output similar to:
Current project directory:
/Users/you/projects/my-new-cli
Contents:
[dir] node_modules
[file] package.json
[file] tsconfig.json
...Development workflow
One-time build
Compiles TypeScript and bundles everything into dist/index.js.
npm run buildLive build (watch mode)
Re-compiles automatically every time you save a file in src/.
npm run devLeave this running in a terminal while you edit src/index.ts. Each save triggers a rebuild, so you can test changes immediately with node dist/index.js.
Type checking
Runs the TypeScript compiler without emitting files, just to catch type errors.
npm run typecheckTesting locally
Option A — npm link (recommended for repeated testing)
npm link installs your package globally on your machine, making the command available everywhere as if it were published to npm.
Step 1 — register the package globally from your template directory:
cd /path/to/my-new-cli
npm run build # dist/ must exist before linking
npm linkStep 2 — use the command from any directory:
cd /some/other/project
my-commandTo unlink when you are done:
npm unlink -g my-commandIf you rename the command in
package.jsonyou must re-runnpm link.
Option B — npx with a local path (no global install)
npm run build
npx /path/to/my-new-cliThis is useful for quick one-off tests without touching your global npm environment.
Option C — run the compiled file directly
node dist/index.jsInstalling in another project
From npm (after publishing)
# As a dev dependency (tool used during development)
npm install --save-dev my-command
# As a regular dependency
npm install my-commandThen run it via an npm script in that project's package.json:
{
"scripts": {
"my-script": "my-command"
}
}Or invoke it directly through npm:
npx my-commandFrom a local path (before publishing)
Useful when you want to test your CLI inside another project without publishing to npm first.
cd /path/to/other-project
npm install /path/to/my-new-cliThen run:
npx my-command
# or add it to scripts in package.json and use: npm run my-scriptPublishing to npm
First-time setup
- Create an account at npmjs.com if you don't have one.
- Log in from your terminal:
npm login
Publish
npm run build # always build before publishing
npm publishFor scoped packages (e.g. @your-username/my-command):
npm publish --access publicUpdating the version
npm version patch # 0.1.0 → 0.1.1 (bug fix)
npm version minor # 0.1.0 → 0.2.0 (new feature)
npm version major # 0.1.0 → 1.0.0 (breaking change)
npm publish
npm versionautomatically commits and tags the version bump in git.
Customizing — renaming your command
Everything that needs to change when you rename my-command to something else:
1. package.json — three fields
{
"name": "your-package-name",
"description": "What your tool does",
"bin": {
"your-command-name": "./dist/index.js"
}
}name— the npm package name (what peoplenpm install).binkey — the executable name (what people type in the terminal).
They can be different. For example: package name is @acme/tools, bin key is acme.
2. Re-link if you used npm link
npm unlink -g my-command
npm link3. That's it
src/index.ts and all build configuration stay the same.
How process.cwd() works
process.cwd() returns the current working directory of the shell that invoked the command, not the directory where your package lives.
/home/user/projects/my-app/ ← process.cwd() when run from here
└── node_modules/
└── my-command/ ← __dirname / import.meta.url point here
└── dist/
└── index.jsThis means your CLI always knows where the user is, regardless of where npm installed it. Use process.cwd() to:
- Read config files from the caller's project (e.g.
path.join(process.cwd(), 'package.json')) - Generate files inside the caller's project
- Walk the caller's directory tree
Do not use __dirname for this purpose — __dirname points at your package's installation directory.
Scripts reference
| Script | Command | Description |
|--------|---------|-------------|
| build | tsup | Compile src/ to dist/ once |
| dev | tsup --watch | Rebuild on every file save |
| start | node dist/index.js | Run the compiled binary |
| typecheck | tsc --noEmit | Type-check without emitting files |
| prepare | npm run build | Runs automatically before npm publish and after npm install from a git URL |
