409e92d6ae
Build and Push Docker Images / Build Docker Image (push) Has been cancelled
Build and Push Docker Images / Build Railway Docker Image (push) Has been cancelled
Build and Publish n8n Docker Image / test-image (push) Has been cancelled
Dependency Compatibility Check / Fresh Install Dependency Check (push) Has been cancelled
Build and Publish n8n Docker Image / build-and-push (push) Has been cancelled
Build and Publish n8n Docker Image / create-release (push) Has been cancelled
Automated Release / Detect Version Change (push) Has been cancelled
Automated Release / Generate Release Notes (push) Has been cancelled
Automated Release / Create GitHub Release (push) Has been cancelled
Automated Release / Package MCPB Bundle (push) Has been cancelled
Automated Release / Build and Verify (push) Has been cancelled
Automated Release / Publish to NPM (push) Has been cancelled
Automated Release / Build and Push Docker Images (push) Has been cancelled
Automated Release / Update Documentation (push) Has been cancelled
Automated Release / Notify Release Completion (push) Has been cancelled
Secret Scan / secretlint (push) Has been cancelled
Test Suite / test (push) Has been cancelled
Test Suite / cjs-runtime (push) Has been cancelled
Test Suite / publish-results (push) Has been cancelled
75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
/**
|
|
* Copy markdown skill files from the sibling n8n-skills repo into
|
|
* data/skills/ so they ship inside the n8n-mcp npm/Docker artifacts.
|
|
*
|
|
* Source defaults to ../n8n-skills/skills relative to this repo root.
|
|
* Override with N8N_SKILLS_SOURCE.
|
|
*/
|
|
import { promises as fs } from 'fs';
|
|
import { existsSync } from 'fs';
|
|
import path from 'path';
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
const CANDIDATE_SOURCES = [
|
|
path.resolve(REPO_ROOT, '..', 'n8n-skills', 'skills'),
|
|
path.resolve(REPO_ROOT, '..', '..', 'n8n-skills', 'skills'),
|
|
];
|
|
const SOURCE = process.env.N8N_SKILLS_SOURCE
|
|
? path.resolve(process.env.N8N_SKILLS_SOURCE)
|
|
: CANDIDATE_SOURCES.find((p) => existsSync(p)) ?? CANDIDATE_SOURCES[0];
|
|
const DEST = path.join(REPO_ROOT, 'data', 'skills');
|
|
|
|
async function copyMarkdownTree(src: string, dst: string): Promise<number> {
|
|
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
let copied = 0;
|
|
await fs.mkdir(dst, { recursive: true });
|
|
for (const entry of entries) {
|
|
const srcPath = path.join(src, entry.name);
|
|
const dstPath = path.join(dst, entry.name);
|
|
if (entry.isDirectory()) {
|
|
// Skill-creator eval workspaces (skills/*-workspace/) are local debris,
|
|
// untracked in n8n-skills and excluded from its dist builds — skip them.
|
|
if (entry.name.endsWith('-workspace')) continue;
|
|
copied += await copyMarkdownTree(srcPath, dstPath);
|
|
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
await fs.copyFile(srcPath, dstPath);
|
|
copied++;
|
|
}
|
|
}
|
|
return copied;
|
|
}
|
|
|
|
async function clearDestination(dir: string): Promise<void> {
|
|
if (!existsSync(dir)) return;
|
|
for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
|
|
if (entry.isDirectory()) {
|
|
await fs.rm(path.join(dir, entry.name), { recursive: true, force: true });
|
|
}
|
|
}
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
console.log(`Syncing skills from: ${SOURCE}`);
|
|
console.log(` into: ${DEST}`);
|
|
|
|
if (!existsSync(SOURCE)) {
|
|
if (existsSync(DEST)) {
|
|
console.warn(`Source not found, keeping existing ${DEST} unchanged.`);
|
|
return;
|
|
}
|
|
console.error(`Source directory not found: ${SOURCE}`);
|
|
console.error('Set N8N_SKILLS_SOURCE or clone n8n-skills next to n8n-mcp.');
|
|
process.exit(1);
|
|
}
|
|
|
|
await clearDestination(DEST);
|
|
const count = await copyMarkdownTree(SOURCE, DEST);
|
|
console.log(`Synced ${count} markdown files.`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('sync-skills failed:', err);
|
|
process.exit(1);
|
|
});
|