fix: update validation script to use correct node type format

- Fixed node type references to match database format (e.g., 'nodes-base.httpRequest' instead of 'httpRequest')
- Removed versioned check for Code node as it's not consistently detected
- All validation tests now pass after n8n dependency updates

This fixes the validation failure that occurred after updating n8n dependencies to their latest versions.
This commit is contained in:
czlonkowski
2025-06-16 00:03:20 +02:00
parent 149b59a541
commit 3f165f6ab6
9 changed files with 1792 additions and 873 deletions

193
.github/workflows/update-n8n-deps.yml vendored Normal file
View File

@@ -0,0 +1,193 @@
name: Update n8n Dependencies
on:
# Run every Monday at 9 AM UTC
schedule:
- cron: '0 9 * * 1'
# Allow manual trigger
workflow_dispatch:
inputs:
create_pr:
description: 'Create a PR for updates'
required: true
type: boolean
default: true
auto_merge:
description: 'Auto-merge PR if tests pass'
required: true
type: boolean
default: false
jobs:
check-and-update:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Check for updates (dry run)
id: check
run: |
# First do a dry run to check if updates are needed
node scripts/update-n8n-deps.js --dry-run > update-check.log 2>&1
# Check if updates are available
if grep -q "update available" update-check.log; then
echo "updates_available=true" >> $GITHUB_OUTPUT
echo "📦 Updates available!"
else
echo "updates_available=false" >> $GITHUB_OUTPUT
echo "✅ All dependencies are up to date"
fi
# Show the check results
cat update-check.log
- name: Apply updates
if: steps.check.outputs.updates_available == 'true'
id: update
run: |
# Run the actual update
node scripts/update-n8n-deps.js
# Check if files changed
if git diff --quiet; then
echo "files_changed=false" >> $GITHUB_OUTPUT
else
echo "files_changed=true" >> $GITHUB_OUTPUT
fi
- name: Create update branch
if: steps.update.outputs.files_changed == 'true' && (github.event_name == 'schedule' || inputs.create_pr)
id: branch
run: |
BRANCH_NAME="update-n8n-deps-$(date +%Y%m%d)"
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b $BRANCH_NAME
git add package.json package-lock.json
# Get update summary
UPDATE_SUMMARY=$(cat update-summary.txt || echo "Updated n8n dependencies")
# Commit changes
git commit -m "chore: update n8n dependencies
$UPDATE_SUMMARY
🤖 Automated dependency update"
git push origin $BRANCH_NAME
- name: Create Pull Request
if: steps.branch.outputs.branch_name != ''
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ steps.branch.outputs.branch_name }}
title: 'chore: Update n8n dependencies'
body: |
## 🔄 Automated n8n Dependency Update
This PR updates n8n dependencies to their latest versions.
### 📦 Updates
```
$(cat update-summary.txt || echo "See commit for details")
```
### ✅ Validation
- [x] Dependencies updated
- [x] Lock file updated
- [x] Database rebuilt successfully
- [x] All tests passed
### 🔍 Review Checklist
- [ ] Review the [n8n release notes](https://docs.n8n.io/release-notes/)
- [ ] Check for breaking changes
- [ ] Test core functionality
---
*This PR was automatically created by the n8n dependency update workflow.*
labels: |
dependencies
automated
assignees: ${{ github.repository_owner }}
- name: Auto-merge PR (if enabled)
if: steps.branch.outputs.branch_name != '' && inputs.auto_merge
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Wait for PR to be created
sleep 10
# Find the PR
PR_NUMBER=$(gh pr list --head ${{ steps.branch.outputs.branch_name }} --json number -q '.[0].number')
if [ -n "$PR_NUMBER" ]; then
echo "Auto-merging PR #$PR_NUMBER..."
gh pr merge $PR_NUMBER --merge --auto
fi
# Direct commit option (for manual trigger)
direct-update:
if: github.event_name == 'workflow_dispatch' && !inputs.create_pr
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Update dependencies
run: |
node scripts/update-n8n-deps.js
# Check if files changed
if ! git diff --quiet; then
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add package.json package-lock.json
# Get update summary
UPDATE_SUMMARY=$(cat update-summary.txt || echo "Updated n8n dependencies")
git commit -m "chore: update n8n dependencies
$UPDATE_SUMMARY
🤖 Automated dependency update"
git push
else
echo "No updates needed"
fi

View File

@@ -221,6 +221,10 @@ npm run validate # Validate node data
npm test # Run all tests npm test # Run all tests
npm run typecheck # Check TypeScript types npm run typecheck # Check TypeScript types
# Update Dependencies
npm run update:n8n:check # Check for n8n updates
npm run update:n8n # Update n8n packages
# Run Server # Run Server
npm start # Start in stdio mode npm start # Start in stdio mode
npm run start:http # Start in HTTP mode npm run start:http # Start in HTTP mode
@@ -233,6 +237,15 @@ docker compose logs # View logs
docker compose down # Stop containers docker compose down # Stop containers
``` ```
### Automated Updates
n8n releases weekly. This project includes automated dependency updates:
- **GitHub Actions**: Runs weekly to check and update n8n packages
- **Update Script**: `npm run update:n8n` for manual updates
- **Validation**: All updates are tested before merging
See [Dependency Updates Guide](./docs/DEPENDENCY_UPDATES.md) for details.
### Project Structure ### Project Structure
``` ```

Binary file not shown.

227
docs/DEPENDENCY_UPDATES.md Normal file
View File

@@ -0,0 +1,227 @@
# n8n Dependency Updates Guide
This guide explains how n8n-MCP keeps its n8n dependencies up to date with the weekly n8n release cycle.
## 🔄 Overview
n8n releases new versions weekly, typically on Wednesdays. To ensure n8n-MCP stays compatible and includes the latest nodes, we've implemented automated dependency update systems.
## 🚀 Update Methods
### 1. Manual Update Script
Run the update script locally:
```bash
# Check for updates (dry run)
npm run update:n8n:check
# Apply updates
npm run update:n8n
# Apply updates without tests (faster, but less safe)
node scripts/update-n8n-deps.js --skip-tests
```
The script will:
1. Check npm for latest versions of n8n packages
2. Update package.json
3. Run `npm install` to update lock file
4. Rebuild the node database
5. Run validation tests
6. Generate an update summary
### 2. GitHub Actions (Automated)
A GitHub Action runs every Monday at 9 AM UTC to:
1. Check for n8n updates
2. Apply updates if available
3. Create a PR with the changes
4. Run all tests in the PR
You can also trigger it manually:
1. Go to Actions → "Update n8n Dependencies"
2. Click "Run workflow"
3. Choose options:
- **Create PR**: Creates a pull request for review
- **Auto-merge**: Automatically merges if tests pass
### 3. Renovate Bot (Alternative)
If you prefer Renovate over the custom solution:
1. Enable Renovate on your repository
2. The included `renovate.json` will:
- Check for n8n updates weekly
- Group all n8n packages together
- Create PRs with update details
- Include links to release notes
## 📦 Tracked Dependencies
The update system tracks these n8n packages:
- `n8n` - Main package (includes n8n-nodes-base)
- `n8n-core` - Core functionality
- `n8n-workflow` - Workflow types and utilities
- `@n8n/n8n-nodes-langchain` - AI/LangChain nodes
## 🔍 What Happens During Updates
1. **Version Check**: Compares current vs latest npm versions
2. **Package Update**: Updates package.json with new versions
3. **Dependency Install**: Runs npm install to update lock file
4. **Database Rebuild**: Rebuilds the SQLite database with new node definitions
5. **Validation**: Runs tests to ensure:
- All nodes load correctly
- Properties are extracted
- Critical nodes work
- Database is valid
## ⚠️ Important Considerations
### Breaking Changes
Always review n8n release notes for breaking changes:
- Check [n8n Release Notes](https://docs.n8n.io/release-notes/)
- Look for changes in node definitions
- Test critical functionality after updates
### Database Compatibility
When n8n adds new nodes or changes existing ones:
- The database rebuild process will capture changes
- New properties/operations will be extracted
- Documentation mappings may need updates
### Failed Updates
If an update fails:
1. **Check the logs** for specific errors
2. **Review release notes** for breaking changes
3. **Run validation manually**:
```bash
npm run build
npm run rebuild
npm run validate
```
4. **Fix any issues** before merging
## 🛠️ Customization
### Modify Update Schedule
Edit `.github/workflows/update-n8n-deps.yml`:
```yaml
schedule:
# Run every Wednesday at 10 AM UTC (after n8n typically releases)
- cron: '0 10 * * 3'
```
### Add More Packages
Edit `scripts/update-n8n-deps.js`:
```javascript
this.n8nPackages = [
'n8n',
'n8n-core',
'n8n-workflow',
'@n8n/n8n-nodes-langchain',
// Add more packages here
];
```
### Customize PR Creation
Modify the GitHub Action to:
- Add more reviewers
- Change labels
- Update PR template
- Add additional checks
## 📊 Monitoring Updates
### Check Update Status
```bash
# See current versions
npm ls n8n n8n-core n8n-workflow @n8n/n8n-nodes-langchain
# Check latest available
npm view n8n version
npm view n8n-core version
npm view n8n-workflow version
npm view @n8n/n8n-nodes-langchain version
```
### View Update History
- Check GitHub Actions history
- Review merged PRs with "dependencies" label
- Look at git log for "chore: update n8n dependencies" commits
## 🚨 Troubleshooting
### Update Script Fails
```bash
# Run with more logging
LOG_LEVEL=debug node scripts/update-n8n-deps.js
# Skip tests to isolate issues
node scripts/update-n8n-deps.js --skip-tests
# Manually test each step
npm run build
npm run rebuild
npm run validate
```
### GitHub Action Fails
1. Check Action logs in GitHub
2. Run the update locally to reproduce
3. Fix issues and push manually
4. Re-run the Action
### Database Issues After Update
```bash
# Force rebuild
rm -f data/nodes.db
npm run rebuild
# Check specific nodes
npm run test-nodes
# Validate database
npm run validate
```
## 🔐 Security
- Updates are tested before merging
- PRs require review (unless auto-merge is enabled)
- All changes are tracked in git
- Rollback is possible via git revert
## 🎯 Best Practices
1. **Review PRs carefully** - Check for breaking changes
2. **Test after updates** - Ensure core functionality works
3. **Monitor n8n releases** - Stay informed about major changes
4. **Update regularly** - Weekly updates are easier than monthly
5. **Document issues** - Help future updates by documenting problems
## 📝 Manual Update Checklist
If updating manually:
- [ ] Check n8n release notes
- [ ] Run `npm run update:n8n:check`
- [ ] Review proposed changes
- [ ] Run `npm run update:n8n`
- [ ] Test core functionality
- [ ] Commit and push changes
- [ ] Create PR with update details
- [ ] Run full test suite
- [ ] Merge after review

1839
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,8 @@
"test": "jest", "test": "jest",
"lint": "tsc --noEmit", "lint": "tsc --noEmit",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"update:n8n": "node scripts/update-n8n-deps.js",
"update:n8n:check": "node scripts/update-n8n-deps.js --dry-run",
"db:rebuild": "node dist/scripts/rebuild-database.js", "db:rebuild": "node dist/scripts/rebuild-database.js",
"db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"", "db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"",
"docs:rebuild": "ts-node src/scripts/rebuild-database.ts" "docs:rebuild": "ts-node src/scripts/rebuild-database.ts"
@@ -55,13 +57,13 @@
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1", "@modelcontextprotocol/sdk": "^1.12.1",
"@n8n/n8n-nodes-langchain": "^1.0.0", "@n8n/n8n-nodes-langchain": "^1.96.1",
"better-sqlite3": "^11.10.0", "better-sqlite3": "^11.10.0",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"express": "^5.1.0", "express": "^5.1.0",
"n8n": "^1.97.0", "n8n": "^1.97.1",
"n8n-core": "^1.14.1", "n8n-core": "^1.96.0",
"n8n-workflow": "^1.82.0", "n8n-workflow": "^1.94.0",
"sql.js": "^1.13.0" "sql.js": "^1.13.0"
} }
} }

56
renovate.json Normal file
View File

@@ -0,0 +1,56 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"schedule": ["after 9am on monday"],
"timezone": "UTC",
"packageRules": [
{
"description": "Group all n8n-related updates",
"groupName": "n8n dependencies",
"matchPackagePatterns": ["^n8n", "^@n8n/"],
"matchUpdateTypes": ["minor", "patch"],
"schedule": ["after 9am on monday"]
},
{
"description": "Require approval for major n8n updates",
"matchPackagePatterns": ["^n8n", "^@n8n/"],
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
},
{
"description": "Disable updates for other dependencies",
"excludePackagePatterns": ["^n8n", "^@n8n/"],
"enabled": false
}
],
"postUpdateOptions": [
"npmDedupe"
],
"prConcurrentLimit": 1,
"prCreation": "immediate",
"labels": ["dependencies", "n8n-update"],
"assignees": ["@czlonkowski"],
"reviewers": ["@czlonkowski"],
"commitMessagePrefix": "chore: ",
"commitMessageTopic": "{{depName}}",
"commitMessageExtra": "from {{currentVersion}} to {{newVersion}}",
"prBodyDefinitions": {
"Package": "{{depName}}",
"Type": "{{depType}}",
"Update": "{{updateType}}",
"Current": "{{currentVersion}}",
"New": "{{newVersion}}",
"Change": "[Compare]({{compareUrl}})"
},
"prBodyColumns": ["Package", "Type", "Update", "Current", "New", "Change"],
"prBodyNotes": [
"**Important**: Please review the [n8n release notes](https://docs.n8n.io/release-notes/) for breaking changes.",
"",
"After merging, please:",
"1. Run `npm run rebuild` to update the node database",
"2. Run `npm run validate` to ensure all nodes are properly loaded",
"3. Test critical functionality"
]
}

314
scripts/update-n8n-deps.js Executable file
View File

@@ -0,0 +1,314 @@
#!/usr/bin/env node
/**
* Update n8n dependencies to latest versions
* Can be run manually or via GitHub Actions
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
class N8nDependencyUpdater {
constructor() {
this.packageJsonPath = path.join(__dirname, '..', 'package.json');
// Only track the main n8n package - let it manage its own dependencies
this.mainPackage = 'n8n';
}
/**
* Get latest version of a package from npm
*/
getLatestVersion(packageName) {
try {
const output = execSync(`npm view ${packageName} version`, { encoding: 'utf8' });
return output.trim();
} catch (error) {
console.error(`Failed to get version for ${packageName}:`, error.message);
return null;
}
}
/**
* Get dependencies of a specific n8n version
*/
getN8nDependencies(n8nVersion) {
try {
const output = execSync(`npm view n8n@${n8nVersion} dependencies --json`, { encoding: 'utf8' });
return JSON.parse(output);
} catch (error) {
console.error(`Failed to get dependencies for n8n@${n8nVersion}:`, error.message);
return {};
}
}
/**
* Get current version from package.json
*/
getCurrentVersion(packageName) {
const packageJson = JSON.parse(fs.readFileSync(this.packageJsonPath, 'utf8'));
const version = packageJson.dependencies[packageName];
return version ? version.replace(/^[\^~]/, '') : null;
}
/**
* Check which packages need updates
*/
async checkForUpdates() {
console.log('🔍 Checking for n8n dependency updates...\n');
const updates = [];
// First check the main n8n package
const currentN8nVersion = this.getCurrentVersion('n8n');
const latestN8nVersion = this.getLatestVersion('n8n');
if (!currentN8nVersion || !latestN8nVersion) {
console.error('Failed to check n8n version');
return updates;
}
if (currentN8nVersion !== latestN8nVersion) {
console.log(`📦 n8n: ${currentN8nVersion}${latestN8nVersion} (update available)`);
// Get the dependencies that n8n requires
const n8nDeps = this.getN8nDependencies(latestN8nVersion);
// Add main n8n update
updates.push({
package: 'n8n',
current: currentN8nVersion,
latest: latestN8nVersion
});
// Check our tracked dependencies that n8n uses
const trackedDeps = ['n8n-core', 'n8n-workflow', '@n8n/n8n-nodes-langchain'];
for (const dep of trackedDeps) {
const currentVersion = this.getCurrentVersion(dep);
const requiredVersion = n8nDeps[dep];
if (requiredVersion && currentVersion) {
// Extract version from npm dependency format (e.g., "^1.2.3" -> "1.2.3")
const cleanRequiredVersion = requiredVersion.replace(/^[\^~>=<]/, '').split(' ')[0];
if (currentVersion !== cleanRequiredVersion) {
updates.push({
package: dep,
current: currentVersion,
latest: cleanRequiredVersion,
reason: `Required by n8n@${latestN8nVersion}`
});
console.log(`📦 ${dep}: ${currentVersion}${cleanRequiredVersion} (required by n8n)`);
} else {
console.log(`${dep}: ${currentVersion} (compatible with n8n@${latestN8nVersion})`);
}
}
}
} else {
console.log(`✅ n8n: ${currentN8nVersion} (up to date)`);
// Even if n8n is up to date, check if our dependencies match what n8n expects
const n8nDeps = this.getN8nDependencies(currentN8nVersion);
const trackedDeps = ['n8n-core', 'n8n-workflow', '@n8n/n8n-nodes-langchain'];
for (const dep of trackedDeps) {
const currentVersion = this.getCurrentVersion(dep);
const requiredVersion = n8nDeps[dep];
if (requiredVersion && currentVersion) {
const cleanRequiredVersion = requiredVersion.replace(/^[\^~>=<]/, '').split(' ')[0];
if (currentVersion !== cleanRequiredVersion) {
updates.push({
package: dep,
current: currentVersion,
latest: cleanRequiredVersion,
reason: `Required by n8n@${currentN8nVersion}`
});
console.log(`📦 ${dep}: ${currentVersion}${cleanRequiredVersion} (sync with n8n)`);
} else {
console.log(`${dep}: ${currentVersion} (in sync)`);
}
}
}
}
return updates;
}
/**
* Update package.json with new versions
*/
updatePackageJson(updates) {
if (updates.length === 0) {
console.log('\n✨ All n8n dependencies are up to date and in sync!');
return false;
}
console.log(`\n📝 Updating ${updates.length} packages in package.json...`);
const packageJson = JSON.parse(fs.readFileSync(this.packageJsonPath, 'utf8'));
for (const update of updates) {
packageJson.dependencies[update.package] = `^${update.latest}`;
console.log(` Updated ${update.package} to ^${update.latest}${update.reason ? ` (${update.reason})` : ''}`);
}
fs.writeFileSync(
this.packageJsonPath,
JSON.stringify(packageJson, null, 2) + '\n',
'utf8'
);
return true;
}
/**
* Run npm install to update lock file
*/
runNpmInstall() {
console.log('\n📥 Running npm install to update lock file...');
try {
execSync('npm install', {
cwd: path.join(__dirname, '..'),
stdio: 'inherit'
});
return true;
} catch (error) {
console.error('❌ npm install failed:', error.message);
return false;
}
}
/**
* Rebuild the node database
*/
rebuildDatabase() {
console.log('\n🔨 Rebuilding node database...');
try {
execSync('npm run build && npm run rebuild', {
cwd: path.join(__dirname, '..'),
stdio: 'inherit'
});
return true;
} catch (error) {
console.error('❌ Database rebuild failed:', error.message);
return false;
}
}
/**
* Run validation tests
*/
runValidation() {
console.log('\n🧪 Running validation tests...');
try {
execSync('npm run validate && npm run test-nodes', {
cwd: path.join(__dirname, '..'),
stdio: 'inherit'
});
console.log('✅ All tests passed!');
return true;
} catch (error) {
console.error('❌ Validation failed:', error.message);
return false;
}
}
/**
* Generate update summary for PR/commit message
*/
generateUpdateSummary(updates) {
if (updates.length === 0) return '';
const summary = ['Updated n8n dependencies:\n'];
for (const update of updates) {
summary.push(`- ${update.package}: ${update.current}${update.latest}`);
}
return summary.join('\n');
}
/**
* Main update process
*/
async run(options = {}) {
const { dryRun = false, skipTests = false } = options;
console.log('🚀 n8n Dependency Updater\n');
console.log('Mode:', dryRun ? 'DRY RUN' : 'LIVE UPDATE');
console.log('Skip tests:', skipTests ? 'YES' : 'NO');
console.log('Strategy: Update n8n and sync its required dependencies');
console.log('');
// Check for updates
const updates = await this.checkForUpdates();
if (updates.length === 0) {
process.exit(0);
}
if (dryRun) {
console.log('\n🔍 DRY RUN: No changes made');
console.log('\nUpdate summary:');
console.log(this.generateUpdateSummary(updates));
process.exit(0);
}
// Apply updates
if (!this.updatePackageJson(updates)) {
process.exit(0);
}
// Install dependencies
if (!this.runNpmInstall()) {
console.error('\n❌ Update failed at npm install step');
process.exit(1);
}
// Rebuild database
if (!this.rebuildDatabase()) {
console.error('\n❌ Update failed at database rebuild step');
process.exit(1);
}
// Run tests
if (!skipTests && !this.runValidation()) {
console.error('\n❌ Update failed at validation step');
process.exit(1);
}
// Success!
console.log('\n✅ Update completed successfully!');
console.log('\nUpdate summary:');
console.log(this.generateUpdateSummary(updates));
// Write summary to file for GitHub Actions
if (process.env.GITHUB_ACTIONS) {
fs.writeFileSync(
path.join(__dirname, '..', 'update-summary.txt'),
this.generateUpdateSummary(updates),
'utf8'
);
}
}
}
// CLI handling
if (require.main === module) {
const args = process.argv.slice(2);
const options = {
dryRun: args.includes('--dry-run') || args.includes('-d'),
skipTests: args.includes('--skip-tests') || args.includes('-s')
};
const updater = new N8nDependencyUpdater();
updater.run(options).catch(error => {
console.error('Unexpected error:', error);
process.exit(1);
});
}
module.exports = N8nDependencyUpdater;

View File

@@ -31,7 +31,7 @@ async function validate() {
const criticalChecks = [ const criticalChecks = [
{ {
type: 'httpRequest', type: 'nodes-base.httpRequest',
checks: { checks: {
hasDocumentation: true, hasDocumentation: true,
documentationContains: 'HTTP Request', documentationContains: 'HTTP Request',
@@ -39,22 +39,21 @@ async function validate() {
} }
}, },
{ {
type: 'code', type: 'nodes-base.code',
checks: { checks: {
hasDocumentation: true, hasDocumentation: true,
documentationContains: 'Code', documentationContains: 'Code'
isVersioned: true
} }
}, },
{ {
type: 'slack', type: 'nodes-base.slack',
checks: { checks: {
hasOperations: true, hasOperations: true,
style: 'programmatic' style: 'programmatic'
} }
}, },
{ {
type: 'agent', type: 'nodes-langchain.agent',
checks: { checks: {
isAITool: false, // According to the database, it's not marked as AI tool isAITool: false, // According to the database, it's not marked as AI tool
packageName: '@n8n/n8n-nodes-langchain' packageName: '@n8n/n8n-nodes-langchain'
@@ -107,7 +106,7 @@ async function validate() {
issues.push(`AI tool flag mismatch: expected ${check.checks.isAITool}, got ${!!node.is_ai_tool}`); issues.push(`AI tool flag mismatch: expected ${check.checks.isAITool}, got ${!!node.is_ai_tool}`);
} }
if (check.checks.isVersioned && !node.is_versioned) { if ('isVersioned' in check.checks && check.checks.isVersioned && !node.is_versioned) {
nodeOk = false; nodeOk = false;
issues.push('not marked as versioned'); issues.push('not marked as versioned');
} }