Skip to content

Commit a724566

Browse files
ssccioclaude
andcommitted
Initial commit: n8n community node for OpenCode AI integration
Add n8n community node that integrates OpenCode AI coding agents as LangChain chat models. This enables using OpenCode's build, chat, and debug agents within n8n workflows. Features: - Custom LangChain chat model wrapper for OpenCode API - Support for multiple providers (Anthropic, OpenAI, Google, Groq, Ollama) - Configurable agent selection (build, chat, debug) - Streaming support via Server-Sent Events - Temperature and max tokens configuration - Optional API key authentication Credential Configuration: - Base URL defaults to http://127.0.0.1:4096 for IPv4 connectivity - Credential test uses POST /session endpoint for validation - Optional API key for authenticated instances Testing: - Unit tests for OpenCodeChatModel - Integration tests with mock server - Pre-commit hooks for code quality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
0 parents  commit a724566

19 files changed

+2738
-0
lines changed

.eslintrc.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module.exports = {
2+
root: true,
3+
env: {
4+
node: true,
5+
es2022: true,
6+
jest: true,
7+
},
8+
parser: '@typescript-eslint/parser',
9+
parserOptions: {
10+
ecmaVersion: 2022,
11+
sourceType: 'module',
12+
project: './tsconfig.json',
13+
},
14+
plugins: ['@typescript-eslint', 'n8n-nodes-base'],
15+
extends: [
16+
'eslint:recommended',
17+
'plugin:@typescript-eslint/recommended',
18+
'plugin:n8n-nodes-base/community',
19+
],
20+
rules: {
21+
'@typescript-eslint/no-explicit-any': 'off',
22+
'@typescript-eslint/no-unused-vars': [
23+
'warn',
24+
{
25+
argsIgnorePattern: '^_',
26+
varsIgnorePattern: '^_',
27+
},
28+
],
29+
'no-console': 'off',
30+
},
31+
ignorePatterns: ['dist', 'node_modules', 'coverage', '*.js'],
32+
};

.github/workflows/ci.yml

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main, develop]
8+
9+
jobs:
10+
lint:
11+
runs-on: [self-hosted, kubernetes]
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: "20"
19+
cache: "npm"
20+
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Run linter
25+
run: npm run lint
26+
27+
build:
28+
runs-on: [self-hosted, kubernetes]
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- name: Setup Node.js
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: "20"
36+
cache: "npm"
37+
38+
- name: Install dependencies
39+
run: npm ci
40+
41+
- name: Build
42+
run: npm run build
43+
44+
- name: Upload build artifacts
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: dist
48+
path: dist/
49+
50+
test:
51+
runs-on: [self-hosted, kubernetes]
52+
needs: build
53+
strategy:
54+
matrix:
55+
node-version: [18, 20, 21]
56+
57+
steps:
58+
- uses: actions/checkout@v4
59+
60+
- name: Setup Node.js ${{ matrix.node-version }}
61+
uses: actions/setup-node@v4
62+
with:
63+
node-version: ${{ matrix.node-version }}
64+
cache: "npm"
65+
66+
- name: Install dependencies
67+
run: npm ci
68+
69+
- name: Run unit tests
70+
run: npm test
71+
env:
72+
CI: true
73+
74+
integration-test:
75+
runs-on: [self-hosted, kubernetes]
76+
needs: build
77+
78+
steps:
79+
- uses: actions/checkout@v4
80+
81+
- name: Setup Node.js
82+
uses: actions/setup-node@v4
83+
with:
84+
node-version: "20"
85+
cache: "npm"
86+
87+
- name: Install dependencies
88+
run: npm ci
89+
90+
- name: Start OpenCode mock server
91+
run: |
92+
npm run test:mock-server &
93+
sleep 5
94+
95+
- name: Run integration tests
96+
run: npm run test:integration
97+
env:
98+
CI: true
99+
OPENCODE_BASE_URL: http://localhost:4096
100+
101+
- name: Stop mock server
102+
if: always()
103+
run: pkill -f mock-server || true
104+
105+
type-check:
106+
runs-on: [self-hosted, kubernetes]
107+
steps:
108+
- uses: actions/checkout@v4
109+
110+
- name: Setup Node.js
111+
uses: actions/setup-node@v4
112+
with:
113+
node-version: "20"
114+
cache: "npm"
115+
116+
- name: Install dependencies
117+
run: npm ci
118+
119+
- name: Type check
120+
run: npm run type-check

.github/workflows/publish.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Publish to npm
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
publish:
9+
runs-on: [self-hosted, kubernetes]
10+
permissions:
11+
contents: read
12+
id-token: write
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: "20"
21+
registry-url: "https://registry.npmjs.org"
22+
cache: "npm"
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Run tests
28+
run: npm test
29+
30+
- name: Build
31+
run: npm run build
32+
33+
- name: Publish to npm
34+
run: npm publish --provenance --access public
35+
env:
36+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
37+
38+
- name: Create GitHub Release Comment
39+
uses: actions/github-script@v7
40+
with:
41+
script: |
42+
github.rest.issues.createComment({
43+
issue_number: context.issue.number,
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
body: '🎉 Published to npm: https://www.npmjs.com/package/n8n-nodes-opencode'
47+
})

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Dependencies
2+
node_modules/
3+
package-lock.json
4+
yarn.lock
5+
pnpm-lock.yaml
6+
7+
# Build output
8+
dist/
9+
*.js
10+
*.d.ts
11+
*.js.map
12+
13+
# But keep these specific files
14+
!.eslintrc.js
15+
16+
# IDE
17+
.vscode/
18+
.idea/
19+
*.swp
20+
*.swo
21+
*~
22+
23+
# OS
24+
.DS_Store
25+
Thumbs.db
26+
27+
# Logs
28+
logs/
29+
*.log
30+
npm-debug.log*
31+
32+
# Environment
33+
.env
34+
.env.local
35+
.env.*.local
36+
37+
# Testing
38+
coverage/
39+
.nyc_output/
40+
41+
# Temporary files
42+
*.tmp
43+
temp/

.markdownlint.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"default": true,
3+
"MD013": false,
4+
"MD040": false,
5+
"MD041": false
6+
}

.pre-commit-config.yaml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
repos:
2+
# Standard pre-commit hooks
3+
- repo: https://github.com/pre-commit/pre-commit-hooks
4+
rev: v6.0.0
5+
hooks:
6+
- id: trailing-whitespace
7+
exclude: ^tests/snapshots/
8+
- id: end-of-file-fixer
9+
exclude: ^tests/snapshots/
10+
- id: check-yaml
11+
- id: check-json
12+
- id: check-added-large-files
13+
args: ["--maxkb=1000"]
14+
- id: check-merge-conflict
15+
- id: detect-private-key
16+
- id: mixed-line-ending
17+
args: ["--fix=lf"]
18+
19+
# ESLint for TypeScript/JavaScript linting
20+
- repo: https://github.com/pre-commit/mirrors-eslint
21+
rev: v9.38.0
22+
hooks:
23+
- id: eslint
24+
files: \.(js|ts|tsx)$
25+
types: [file]
26+
args: ["--fix"]
27+
additional_dependencies:
28+
29+
- "@typescript-eslint/[email protected]"
30+
- "@typescript-eslint/[email protected]"
31+
32+
33+
# TypeScript type checking
34+
- repo: local
35+
hooks:
36+
- id: typescript-check
37+
name: TypeScript type check
38+
entry: npm run type-check
39+
language: system
40+
pass_filenames: false
41+
always_run: true
42+
43+
# Run tests before commit
44+
- repo: local
45+
hooks:
46+
- id: jest-tests
47+
name: Run Jest tests
48+
entry: npm test
49+
language: system
50+
pass_filenames: false
51+
always_run: true
52+
stages: [pre-commit]
53+
54+
# Markdown linting
55+
- repo: https://github.com/igorshubovych/markdownlint-cli
56+
rev: v0.45.0
57+
hooks:
58+
- id: markdownlint
59+
args: ["--fix"]
60+
exclude: ^node_modules/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)