feat: Add @n8n/node-cli package with an empty create command (#17620)

This commit is contained in:
Elias Meire
2025-07-31 00:09:49 +02:00
committed by GitHub
parent 53594a90e4
commit 79c6b60fcb
13 changed files with 268 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
# @n8n/create-node
Scaffold a new community n8n node
## Usage
```bash
npm create @n8n/node
# or
pnpm create @n8n/node
# or
yarn create @n8n/node
```

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
import { createRequire } from 'node:module';
import path from 'node:path';
const require = createRequire(import.meta.url);
const cliBin = require.resolve('@n8n/node-cli/bin/n8n-node.js');
const result = spawnSync('node', [cliBin, 'create', ...process.argv.slice(2)], {
stdio: 'inherit',
});
process.exit(result.status ?? 1);

View File

@@ -0,0 +1,25 @@
{
"private": true,
"type": "module",
"name": "@n8n/create-node",
"version": "0.1.0",
"description": "Official CLI to create new community nodes for n8n",
"bin": {
"create-n8n-node": "./bin/create.js"
},
"files": [
"bin",
"dist"
],
"scripts": {
"publish:dry": "pnpm run build && pnpm pub --dry-run",
"start": "./bin/create.js"
},
"repository": {
"type": "git",
"url": "https://github.com/n8n-io/n8n"
},
"dependencies": {
"@n8n/node-cli": "workspace:*"
}
}

View File

@@ -0,0 +1,11 @@
{
"extends": "@n8n/typescript-config/modern/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "src",
"outDir": "dist",
"types": ["vite/client", "vitest/globals"],
"isolatedModules": true
},
"include": ["src/**/*.ts"]
}

View File

@@ -0,0 +1,35 @@
# @n8n/node-cli
Official CLI for developing community nodes for [n8n](https://n8n.io).
## Features
- 🔧 Scaffold new nodes
- More coming soon
## Installation
Run directly via `npx`:
```bash
npx n8n-node create
```
Or install globally:
```bash
npm install -g @n8n/node-cli
n8n-node create
```
## Commands
## Create a node
```bash
n8n-node create # Scaffold a new node
```
## Related
`@n8n/create-node`: Lightweight wrapper to support `npm create @n8n/node`

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env node
import { execute } from '@oclif/core';
await execute({ dir: import.meta.url });

View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'eslint/config';
import { nodeConfig } from '@n8n/eslint-config/node';
export default defineConfig(nodeConfig, {
files: ['./src/commands/*.ts'],
rules: { 'import-x/no-default-export': 'off' },
});

View File

@@ -0,0 +1,46 @@
{
"private": true,
"type": "module",
"name": "@n8n/node-cli",
"version": "0.1.0",
"description": "Official CLI for developing community nodes for n8n",
"bin": {
"n8n-node": "./bin/n8n-node.js"
},
"files": [
"bin",
"dist"
],
"scripts": {
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"dev": "tsc -w",
"format": "biome format --write src",
"format:check": "biome ci src",
"lint": "eslint src --quiet",
"lintfix": "eslint src --fix",
"build": "tsc",
"publish:dry": "pnpm run build && pnpm pub --dry-run",
"test": "vitest run",
"test:dev": "vitest --silent=false",
"start": "./bin/n8n-node.js"
},
"repository": {
"type": "git",
"url": "https://github.com/n8n-io/n8n"
},
"oclif": {
"bin": "n8n-node",
"commands": "./dist/commands",
"topicSeparator": " "
},
"dependencies": {
"@oclif/core": "^4.5.2",
"prompts": "^2.4.2"
},
"devDependencies": {
"@n8n/typescript-config": "workspace:*",
"@n8n/vitest-config": "workspace:*",
"@oclif/test": "^4.1.13"
}
}

View File

@@ -0,0 +1,8 @@
import { runCommand } from '@oclif/test';
describe('n8n-node create', () => {
it('should print correct output', async () => {
const { stdout } = await runCommand('create -f', { root: import.meta.dirname });
expect(stdout).toEqual('hello from commands/create.ts (force=true)\n');
});
});

View File

@@ -0,0 +1,17 @@
import { Command, Flags } from '@oclif/core';
export default class Create extends Command {
static override description = 'Create a new n8n community node';
static override examples = ['<%= config.bin %> <%= command.id %>'];
static override flags = {
// flag with no value (-f, --force)
force: Flags.boolean({ char: 'f' }),
};
async run(): Promise<void> {
const { flags } = await this.parse(Create);
const force = flags.force;
this.log(`hello from commands/create.ts (force=${force})`);
}
}

View File

@@ -0,0 +1,12 @@
{
"extends": "@n8n/typescript-config/modern/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "src",
"outDir": "dist",
"types": ["vite/client", "vitest/globals"],
"isolatedModules": true
},
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}

View File

@@ -0,0 +1,4 @@
import { vitestConfig } from '@n8n/vitest-config/node';
import { defineConfig, mergeConfig } from 'vitest/config';
export default defineConfig({ test: { globals: true, disableConsoleIntercept: true } });