Compare commits

...

785 Commits

Author SHA1 Message Date
Albert Alises
22f2e34fe6
fix(core): Stop workflow builder after terminal remediation (#30289)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-12 13:53:18 +00:00
Jon
d06110ba9d
feat(Facebook Graph API Node): Add OAuth2 support (#27112)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-05-12 13:32:08 +00:00
Jaakko Husso
0ce820de73
fix(core): Abort orchestrator run after repeated plan-guard rejections (no-changelog) (#30274) 2026-05-12 12:11:17 +00:00
Alex Grozav
f0649e0a3d
refactor(editor): Add executionData store for per-execution state (no-changelog) (#29757) 2026-05-12 11:53:43 +00:00
Matsu
28df864aab
chore: Bump fast-uri override to 3.1.2 (#30307) 2026-05-12 11:41:40 +00:00
Michael Kret
27d72acae5
feat: Track n8n Connect credential toggle in telemetry (no-changelog) (#30245) 2026-05-12 11:09:29 +00:00
Declan Carroll
cd0519f360
chore: Skip scaffolding templates in code-health and swap to catalog refs (no-changelog) (#30297) 2026-05-12 10:58:00 +00:00
Matsu
c158771d5f
ci: Allow removal of deprecated release candidate branches (#30058) 2026-05-12 10:48:35 +00:00
Matsu
c0be06f9ff
ci: Migrate from actions/attest-sbom to actions/attest (#30304) 2026-05-12 10:45:58 +00:00
Charlie Kolb
d5d51731d2
fix(editor): Sanitize workflow created during sub-workflow conversion (#30208) 2026-05-12 10:27:52 +00:00
Dawid Myslak
fb78047d9a
fix(core): Add origin-only fallback to MCP OAuth discovery for path-bearing server URLs (#30231)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 10:10:16 +00:00
Matsu
b3760c776f
ci: Skip quality checks on Bot PRs (#30284) 2026-05-12 10:08:40 +00:00
Andreas Fitzek
d2e5db258c
feat(core): Add encrypted secureArtifacts slot to IExecutionContext (no-changelog) (#30125) 2026-05-12 09:58:45 +00:00
bjorger
744bb92c2f
feat(core): Add observational memory runtime, builder, and read path (#29815) 2026-05-12 09:55:52 +00:00
Fendy H
d06bbe4f32
feat(NocoDB Node): Add new data apis and use new api version (#18626) 2026-05-12 09:32:46 +00:00
Milorad FIlipović
54d62bb4a1
fix(core): Update instance-ai evaluator to include pinned subnodes and allow all mcp tools (#30292) 2026-05-12 09:13:01 +00:00
Declan Carroll
a60ef7dbb5
ci: Gate PRs on code-health and janitor checks (#30091)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 09:02:53 +00:00
Konstantin Tieber
111d403aa7
fix(core): Member role getting read permissions for insights (#30291) 2026-05-12 08:53:38 +00:00
Albert Alises
5059ce7e3d
feat(ai-builder): Expose generated workflow IDs on LangSmith trace root metadata (#30262) 2026-05-12 08:37:57 +00:00
Bernhard Wittmann
b445221c6a
feat: Computer-use evaluation harness (no-changelog) (#29797)
Co-authored-by: Elias Meire <elias@meire.dev>
2026-05-12 08:36:12 +00:00
Bernhard Wittmann
dc7dcaf1b1
fix: Show friendly message in computer use cli when connection token is invalid (no-changelog) (#30288) 2026-05-12 08:34:33 +00:00
Marc Littlemore
ab8475b4cf
chore: Revert to old CODEOWNERS (#30290) 2026-05-12 08:19:58 +00:00
RomanDavydchuk
980f3c8461
fix(editor): Improve dedicated MCP tools connection experience (no-changelog) (#30200) 2026-05-12 08:05:48 +00:00
Andreas Fitzek
2b7e313430
feat(core): Add redaction enforcement feature-flag helpers (no-changelog) (#30253) 2026-05-12 08:03:43 +00:00
Andreas Fitzek
0bde73c42f
feat(core): Scaffold inbound-secrets module (no-changelog) (#30093) 2026-05-12 08:03:29 +00:00
Sandra Zollner
1e685062c3
refactor(core): Combine insights by workflow count and page query (#29787)
Co-authored-by: Ali Elkhateeb <ali.elkhateeb@n8n.io>
2026-05-12 08:01:47 +00:00
Eugene
df6e39bddf
feat(editor): Disable Agent editing UI when user lacks agent:update (no-changelog) (#30201)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: yehorkardash <yehor.kardash@n8n.io>
2026-05-12 07:58:12 +00:00
Mutasem Aldmour
3297536011
refactor(core): Move node-specific builder guidance to per-node @builderHint (no-changelog) (#29992)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 07:45:33 +00:00
José Braulio González Valido
95cf41c37c
chore(core): Enable Daytona sandbox in Instance AI evals (no-changelog) (#29931)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 07:43:04 +00:00
n8n-release-tag-merge[bot]
74fb4110c4 Merge tag 'n8n@2.21.0' 2026-05-12 08:02:43 +00:00
n8n-assistant[bot]
61be42c7bb
🚀 Release 2.21.0 (#30283)
Co-authored-by: Matsuuu <16068444+Matsuuu@users.noreply.github.com>
2026-05-12 07:29:34 +00:00
Ricardo Espinoza
b5bafc861e
feat(core): Add update_partial_workflow MCP tool (#29739) 2026-05-12 07:24:49 +00:00
Jon
3dd134ab3c
fix(core): Preserve AxiosHeaders instance when applying OpenAI vendor defaults (#29860)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shireen Missi <94372015+ShireenMissi@users.noreply.github.com>
2026-05-12 07:24:26 +00:00
yehorkardash
e98c1e5fe6
fix(editor): Set document title on agent pages (no-changelog) (#30243) 2026-05-12 07:13:33 +00:00
yehorkardash
ae81d1bac0
fix(core): Resolve global credentials for agents (no-changelog) (#30233) 2026-05-12 07:13:30 +00:00
Matsu
cb019eb253
ci: Add artifact prefix to e2e runs to prevent clashing (#30281) 2026-05-12 07:03:09 +00:00
Ali Elkhateeb
8b0a3ae3d3
feat(core): Enrich agent execution telemetry (no-changelog) (#29914) 2026-05-12 06:25:26 +00:00
Romeo Balta
7fdd98aa72
feat(editor): Add proactive starter experiment (no-changelog) (#30252)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-11 21:32:14 +00:00
Dawid Myslak
133a5aa0ad
feat(Onfleet Trigger Node): Add webhook request verification (#29485) 2026-05-11 21:27:33 +00:00
Dawid Myslak
da41470311
feat(Acuity Scheduling Trigger Node): Add webhook request verification (#29261)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 20:54:07 +00:00
Dawid Myslak
94e403300b
feat(Asana Trigger Node): Add webhook request verification (#29258) 2026-05-11 20:04:15 +00:00
aikido-autofix[bot]
267fe49d51
fix: Fix 15 security issues in fast-xml-builder, basic-ftp, fast-uri and 5 more (#30169)
Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
Co-authored-by: Declan Carroll <declan@n8n.io>
2026-05-11 19:15:47 +00:00
Michael Drury
e968723808
chore(core): Langsmith OTel telemetry for agent builder (#30259) 2026-05-11 18:29:33 +00:00
Albert Alises
bb73952fcc
fix(core): Defer credential setup during workflow builds (#30181) 2026-05-11 15:46:44 +00:00
Michael Drury
9072ee3beb
fix(core): Agents called from workflows use the workflows owner/user ID for calling further workflows through the agent (#30242) 2026-05-11 14:51:59 +00:00
Eugene
1749801508
fix(core): Gate agent node tools behind node-tools-searcher module (no-changelog) (#30237) 2026-05-11 14:49:40 +00:00
Alexander Gekov
a8aa95551e
fix(Git Node): Restore Clone and other operations on simple-git 3.36+ (#30223) 2026-05-11 14:46:30 +00:00
Declan Carroll
c75a45ba15
chore: Sync quarantine list and add hanging instance-ai tests (#30248) 2026-05-11 14:31:17 +00:00
Tomi Turtiainen
0a761355c4
fix(core): Prevent proxy layer accumulation in ObservableObject (#30129) 2026-05-11 14:29:28 +00:00
Raúl Gómez Morales
bad43d0c81
test(editor): Move Instance AI runtime coverage (no-changelog) (#30240) 2026-05-11 14:21:31 +00:00
Rob Hough
b168523254
refactor(editor): Fix small style nits in Agents (#30222) 2026-05-11 13:34:27 +00:00
Svetoslav Dekov
3df6611fb3
chore(editor): Refactoring instance-ai workflow setup FE code (no-changelog) (#30012)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Charlie Kolb <charlie@n8n.io>
2026-05-11 13:33:15 +00:00
Michael Kret
2e046d5b7f
fix(RSS Feed Read Node): Respect proxy settings (#30059) 2026-05-11 13:28:15 +00:00
Milorad FIlipović
0494f24967
feat(core): Track no results in code-builder search tool (no-changelog) (#30165)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-11 13:08:21 +00:00
Milorad FIlipović
e8827cd6e8
fix(core): Improve documentation usage in mcp tools (#30210) 2026-05-11 12:52:56 +00:00
Matsu
b64a84159d
ci: Use cla-signed labels with CLA automations (#30234)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:48:41 +00:00
José Braulio González Valido
5bf5f03453
fix(core): Avoid Agent.close() deadlock in instance-ai web-research fetch (no-changelog) (#30105)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:40:49 +00:00
José Braulio González Valido
3123f2551b
fix(core): Allow same-domain redirects in instance-ai web research (TRUST-73) (#30107)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:40:43 +00:00
Milorad FIlipović
127544ae5b
fix(core): Fix Resource Mapper types in SDK (no-changelog) (#30213) 2026-05-11 12:35:53 +00:00
Bernhard Wittmann
ea98243c2b
feat: Add deeplinkpairing and connection handling for native computer use (no-changelog) (#29445) 2026-05-11 12:35:08 +00:00
Dawid Myslak
2e21c5fcf8
feat(Microsoft Outlook Node): Add location and attendees fields to calendar events (#29844)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-05-11 12:29:49 +00:00
Stephen Wright
7635131bd3
feat(editor): Show locked state and permission notice on data redaction workflow settings (#30022)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-05-11 12:02:59 +00:00
Raúl Gómez Morales
0d571c05e4
refactor(editor): Add Instance AI thread provider (no-changelog) (#30090) 2026-05-11 11:45:19 +00:00
Arvin A
6f9b99a3cf
feat(editor): Eval run detail loading + error states (TRUST-70 follow-up) (#29817)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-05-11 11:36:03 +00:00
Mutasem Aldmour
0feec2fea6
fix(core): Make placeholder() return string (no-changelog) (#30100)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:32:35 +00:00
Garrit Franke
e3e70d6068
feat(Figma Trigger Node): Add OAuth2 authentication support (#30079)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:30:49 +00:00
Matsu
410b75c3d0
ci: Add in-house CLA check workflow (#30209)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:29:11 +00:00
bjorger
75646c4527
fix(core): Clarify agent builder prompt guidance (#30127) 2026-05-11 11:11:51 +00:00
Mutasem Aldmour
d0367a00e8
chore: Align pairwise eval builder with production handover (#30019)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:00:37 +00:00
Michael Drury
7094b48c94
fix(core): Persist agent chat draft across modes and hide unfinished tool-approval toggle (#30123) 2026-05-11 10:53:59 +00:00
Michael Kret
582b6ae9ea
fix(MongoDB Node): Resolve collection parameter per item in write operations (#29956) 2026-05-11 10:16:14 +00:00
Irénée
26beabb445
refactor(core): Split SSO loader (no-changelog) (#30065) 2026-05-11 10:16:02 +00:00
Dawid Myslak
96b018d356
fix(YouTube Node): Fix misspelled "unlisted" privacy status value in Video Update operation (#30203)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:00:29 +00:00
Suguru Inoue
d5d290d706
refactor(editor): Migrate workflow document store init (#30077) 2026-05-11 09:57:07 +00:00
Albert Alises
40ffbfa5ab
feat(ai-builder): Add n8n and workflow SDK versions to LangSmith trace metadata (no-changelog) (#30202) 2026-05-11 09:36:53 +00:00
Daria
94d91e13bf
fix(core): Export boolean CSV values as true/false for Data Tables (#30007) 2026-05-11 09:30:00 +00:00
Yuliia Pominchuk
515ae7ced4
feat(core): Add IP rate limiting to dynamic credential authentication endpoints (#30199) 2026-05-11 09:25:26 +00:00
Albert Alises
52a4bcb23a
fix(core): Add liveness timeouts for Instance AI (#30145) 2026-05-11 09:13:57 +00:00
bjorger
be4ef22533
feat(core): Add observational memory storage foundation (#29814) 2026-05-11 09:01:44 +00:00
Guillaume Jacquart
f4e8088cb8
fix(core): Stop applying node-defined sensitive output fields to runtime data (#30198)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 08:57:42 +00:00
bjorger
174f0f805e
fix(core): Scope credential resolution (#30156) 2026-05-11 08:53:22 +00:00
oleg
c94a403682
feat(core): Add agents SDK telemetry hooks (no-changelog) (#30014) 2026-05-11 08:48:23 +00:00
Alexander Gekov
a30772c933
fix(core): Skip unknown fixedCollection keys instead of throwing (#29689)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 08:33:56 +00:00
RomanDavydchuk
86170674b7
feat(core): Generate service-specific OAuth2 credentials for dedicated MCP tools (#29884)
Co-authored-by: Elias Meire <elias@meire.dev>
2026-05-11 07:29:37 +00:00
Michael Kret
1a22c76270
fix(Schedule Node): Fix hourly intervals that don't divide evenly into 24h (#29778) 2026-05-11 07:28:37 +00:00
Michael Kret
7c1a77154c
fix(Wait Node): Resolve expressions inside Custom HTML form fields (#30060) 2026-05-11 06:51:45 +00:00
Jaakko Husso
f63567b1ec
feat(editor): Land users to instance AI on root if the module is enabled (no-changelog) (#30121) 2026-05-11 06:46:31 +00:00
Raúl Gómez Morales
dd7555d277
refactor(editor): Split Instance AI view into route-driven empty + thread leaves (no-changelog) (#29877) 2026-05-11 06:38:39 +00:00
n8n-assistant[bot]
3bf5d4ac91
chore: Update node popularity data (#30191)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 06:33:04 +00:00
Declan Carroll
3a33a448b0
test(benchmark): Question-driven Playwright benchmark suite with tiered topology and rich diagnostics (#29024)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Lint (push) Has been cancelled
CI: Master (Build, Test, Lint) / Performance (push) Has been cancelled
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Prepare Docker (coverage) (push) Has been cancelled
Util: Update Node Popularity / approve-and-automerge (push) Has been cancelled
Test: E2E Coverage Weekly / E2E (coverage) (push) Has been cancelled
Test: E2E Coverage Weekly / Aggregate Coverage (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (beta) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (stable) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (v1) (push) Has been cancelled
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 21:14:08 +00:00
Ricardo Espinoza
60e23e10e0
fix(core): Avoid MCP get_execution hang on circular references (#30051)
Some checks failed
Build: Benchmark Image / build (push) Has been cancelled
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Lint (push) Has been cancelled
CI: Master (Build, Test, Lint) / Performance (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Has been cancelled
2026-05-08 19:02:34 +00:00
José Braulio González Valido
5e88748334
fix(core): Always create instance-ai sandbox workspace dirs (TRUST-79) (#30106)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:52:44 +00:00
Dawid Myslak
fbf89bde11
feat(GitLab Trigger Node): Add webhook request verification (#29260) 2026-05-08 16:50:00 +00:00
Iván Ovejero
3702ff8eb3
fix(core): Propagate waitTill from worker to main in scaling mode (#30099) 2026-05-08 16:45:58 +00:00
Mike Repeć
d3a3441be2
chore: assign instance-ai cli module to instance-ai team (#30120) 2026-05-08 15:45:18 +00:00
bjorger
8171cf0b32
fix(editor): Disable chat during interactive agent choices (#30111) 2026-05-08 15:14:38 +00:00
Eugene
523fd85e45
feat(editor): Add "New agent" to the universal add menu (no-changelog) (#29978)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 15:10:27 +00:00
Dimitri Lavrenük
bda1782de6
fix: Remove confirmation from browser connect and disconnect tools (no-changelog) (#30096) 2026-05-08 14:43:06 +00:00
Dimitri Lavrenük
1e8f89bd5a
feat: Allow late browser connection after timeout (no-changelog) (#30092) 2026-05-08 14:42:53 +00:00
Jaakko Husso
f709e53824
fix(core): Inline AI_NODE_SDK_VERSION to save memory by not loading @n8n/ai-utilities on boot (#30113) 2026-05-08 14:33:31 +00:00
Rob Hough
f87094cf6e
fix(editor): Add expand/collapse to chat panel in Agents (#30069) 2026-05-08 14:27:46 +00:00
mfsiega
cd5b2b3762
chore(core): Add @n8n/engine HTTP server and harness (no-changelog) (#29913)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 14:08:11 +00:00
Dimitri Lavrenük
8a6e779c6d
fix: Fix browser use tool context in AI Assistant (no-changelog) (#30080) 2026-05-08 13:50:07 +00:00
Daria
277431b88b
fix(editor): Match input height with mode selector in resource locator (#30075) 2026-05-08 13:49:24 +00:00
Danny Martini
9931c4d055
refactor(core): Skip redundant extend helpers in VM mode (no-changelog) (#30098)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:40:15 +00:00
Mutasem Aldmour
72eca2f398
refactor: Rename node-level builderHint.message to searchHint and propertyHint (#30062)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:32:50 +00:00
Jaakko Husso
7e6bca1f13
feat(core): Make instance AI enabled by default for users on the test group, drop opt-in modal (no-changelog) (#30097) 2026-05-08 13:19:49 +00:00
Mike Repeć
e15c091c75
fix(editor): Refactor archive workflow spec to use API helpers for stability (no-changelog) (#30089) 2026-05-08 12:40:59 +00:00
Bernhard Wittmann
ecf96ad30c
fix: Add warning to Computer Use install modal (#30094) 2026-05-08 12:25:54 +00:00
Benjamin Schroth
8116e0a485
feat(core): Add multi-config evaluations backend (#29784) 2026-05-08 12:24:17 +00:00
Mutasem Aldmour
2ece58eee5
chore: Assign workflow-sdk and instance-ai to instance-ai team (#30087)
Co-authored-by: Claude <noreply@anthropic.com>
2026-05-08 12:19:55 +00:00
Dawid Myslak
0cc163b7dc
fix(EditImage Node): Fix composite operation failing with stream empty buffer (#30088)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 12:14:25 +00:00
Albert Alises
ceaebc6cbe
fix(core): Validate AI builder credential IDs before save (#30070)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-08 11:29:12 +00:00
Mutasem Aldmour
afe119be14
fix(core): Improve AI chat file upload handling and error states (#29701)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:26:58 +00:00
Marc Littlemore
cfec60de6a
chore: Clarify decorators ownership (#30085) 2026-05-08 10:59:26 +00:00
Charlie Kolb
2b2fa0aaa3
chore: Move stylelint-config codeowners to qa-dx (no-changelog) (#30084) 2026-05-08 10:28:49 +00:00
Charlie Kolb
4b89faa707
chore: Reassign i18n package codeownership to frontend team (no-changelog) (#30082) 2026-05-08 10:20:36 +00:00
Dawid Myslak
910822fb09
feat(Figma Trigger Node): Add webhook request verification (#29262)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 09:34:11 +00:00
Marc Littlemore
b3a806125b
chore: Improve CODEOWNERS file for automatic team review (#27883) 2026-05-08 09:06:37 +00:00
Suguru Inoue
149bdebf37
refactor(editor): Delete workflow ref from workflows.store.ts (#29531) 2026-05-08 08:54:35 +00:00
Declan Carroll
33c3598e66
ci: Remove unused bin fields to fix pnpm install warnings (no-changelog) (#29586)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 08:47:25 +00:00
Tomi Turtiainen
7c57843cf6
refactor(ai-builder): Replace hand-rolled sandbox client with @n8n/sandbox-client SDK (no-changelog) (#29879) 2026-05-08 08:32:02 +00:00
Eugene
6f4f0a0303
fix(core): Activate agent chat integrations on every main (#30029)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Michael Drury <michael.drury@n8n.io>
2026-05-08 08:11:57 +00:00
Declan Carroll
e7b353cabc
ci: Shard weekly E2E coverage run across cached docker image (no-changelog) (#29337)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:08:39 +00:00
Rob Hough
478d4998a8
fix(editor): Fix Agents styling issues from merge regression (#30032) 2026-05-08 08:06:40 +00:00
Csaba Tuncsik
5cbd2dd1e9
fix(editor): Polish encryption keys settings page (#30008) 2026-05-08 07:44:29 +00:00
Alexander Gekov
d318bc1e33
fix(Notion Node): Paginate Get Many operations beyond 100-item API cap (#29690)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-05-08 07:03:37 +00:00
Declan Carroll
6b893b45a0
fix: Align undici override across major versions (#30028)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 05:51:34 +00:00
Declan Carroll
75ed71c001
fix(core): Add ESLint rule to prevent error instances in toThrow assertions (#29889)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 05:51:05 +00:00
Jaakko Husso
73dae68663
fix(core): Handle browser not being available on computer use gracefully, better pause-for-user tool (no-changelog) (#29995)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (beta) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (stable) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (v1) (push) Has been cancelled
2026-05-07 22:09:29 +00:00
Michael Drury
820128196c
fix(core): Simplify Slack redirect URL verification process for agents (#30033)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-07 18:38:32 +00:00
Jaakko Husso
8e0f37d100
fix(core): Support type filters on global credential lookups (#30002) 2026-05-07 17:50:58 +00:00
Guillaume Jacquart
75053fec93
feat(editor): Add envFeatureFlag and copyButton property options (#29733)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 16:44:17 +00:00
oleg
ffcf63691f
feat(agents): Add reusable workspace edit tools (no-changelog) (#30013) 2026-05-07 16:03:13 +00:00
Irénée
730c3e12a5
feat(core): Define community packages with environment variables (#29961) 2026-05-07 15:56:14 +00:00
Jaakko Husso
e6b37ef06d
fix(core): Make instance AI use the correct instance URL for OAuth callbacks (no-changelog) (#30024) 2026-05-07 15:37:09 +00:00
Jaakko Husso
43438f0361
fix(core): Tighten instance ai mutation and approval gates (no-changelog) (#29750) 2026-05-07 15:36:36 +00:00
Arvin A
9014baea7e
feat(editor): Redesign evaluation run detail page (#29592) 2026-05-07 15:02:59 +00:00
Charlie Kolb
ca33060e0b
fix(core): Advance Postgres IDENTITY sequences after entity import (#29762)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:00:04 +00:00
Eugene
1a270f2f35
fix(editor): Make agent publish indicator dot use correct color (no-changelog) (#29979)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 13:05:07 +00:00
Marc Littlemore
ba5b3d13b1
fix(editor): Render tooltips above popovers (#29997)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 13:02:16 +00:00
Michael Drury
9f92005938
fix(core): Agent sessions correctly quoting columns in queries for Postgres (#29999) 2026-05-07 12:30:12 +00:00
Benjamin Schroth
f7c7acc244
fix(editor): Make sure trimmed placeholder never reaches backend (#29842) 2026-05-07 12:15:27 +00:00
Jon
f871d44cab
fix(Salesforce Node): Fix trigger not firing on repeated record updates (#29107)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-05-07 12:13:57 +00:00
Konstantin Tieber
01300e9b9b
fix(core): Simple-git update broke https connection (#29998) 2026-05-07 12:01:41 +00:00
aikido-autofix[bot]
972d8d4ec7
chore: Bump Axios, hono, vm2 and fast-xml-parser (#29829)
Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
Co-authored-by: Matsuuu <huhta.matias@gmail.com>
2026-05-07 11:54:50 +00:00
José Braulio González Valido
30d9a168bc
feat(ai-builder): Add --prebuilt-workflows flag for eval CLI (no-changelog) (#29830)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:47:29 +00:00
Dawid Myslak
dab3653f80
feat(Microsoft Outlook Node): Add support for recurring event instances (#29802)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 11:45:52 +00:00
Declan Carroll
8573197aef
ci: Scope path-filter and janitor diff to PR-only changes (#29993)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:41:35 +00:00
Michael Kret
0edcdcfe85
fix(Calendly Trigger Node): Use API v2 for webhook subscriptions (#29771) 2026-05-07 11:29:34 +00:00
Jaakko Husso
a316742c92
fix(core): Gate web search tool use behind approval checks correctly (no-changelog) (#29685)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
Co-authored-by: Albert Alises <albert.alises@gmail.com>
2026-05-07 11:06:51 +00:00
Matsu
ad0a6e9d46
ci: Use a configurable json file for safechain options (#29960) 2026-05-07 10:43:24 +00:00
Matsu
db0097c57f
ci: Make Chromatic visual checks non-blocking (no-changelog) (#29965)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:43:14 +00:00
Mike Repeć
5c7921f71c
fix(core): Filter WaitTracker to only poll waiting executions (#29898)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:10:05 +00:00
Garrit Franke
15105610f6
docs: Correct rationale for no-overrides-field ESLint rule (#29973)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:07:14 +00:00
Rob Hough
8474f1e6f3
fix(editor): Change read-only background color so it's visible (no-changelog) (#29971) 2026-05-07 09:58:41 +00:00
Garrit Franke
5abcae686c
feat(Strava Node): Allow custom OAuth2 scopes (#29972)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:57:03 +00:00
Mutasem Aldmour
1cb7c591b3
chore: Match production builder step cap in pairwise eval (#29977)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:53:36 +00:00
Michael Drury
ebafde7f85
feat(core): Show workflow-triggered runs in agent session history (no-changelog) (#29932)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:48:47 +00:00
Dawid Myslak
8f1f42d180
feat(Trello Trigger Node): Add webhook request verification (#29252) 2026-05-07 09:42:45 +00:00
Elias Meire
2dbf02e63e
fix(core): Harden axios error handling against non-string error stack (#29100) 2026-05-07 09:38:13 +00:00
Guillaume Jacquart
7fdc7788d5
test(core): Cover JWE decryption on dynamic-credential OAuth2 callback (#29808)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 09:33:55 +00:00
Dawid Myslak
acc9643811
feat(Twilio Trigger Node): Add webhook request verification (#29259) 2026-05-07 09:00:56 +00:00
Michael Kret
29a864ca9b
fix(HTTP Request Node): Validate URL type in older node versions (#29886) 2026-05-07 08:46:16 +00:00
Guillaume Jacquart
e71afedfab
fix(editor): Rename encryption keys "Type" column to "Status" (#29966)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 08:31:30 +00:00
Arvin A
6232de4d47
feat(editor): Cap eval concurrency slider at admin-set limit (#29807)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 08:31:13 +00:00
Albert Alises
273db4be75
fix(ai-builder): Validate MCP tool names and schemas (no-changelog) (#29871) 2026-05-07 08:25:04 +00:00
Albert Alises
8dd6d12918
fix(ai-builder): Improve filesystem read handling (no-changelog) (#29870) 2026-05-07 08:24:47 +00:00
Albert Alises
be90f9f873
fix(ai-builder): Use expiring Computer Use setup tokens (no-changelog) (#29872) 2026-05-07 08:24:38 +00:00
Albert Alises
5e3aa1a726
fix(ai-builder): Preserve collected planning context (#29916) 2026-05-07 08:24:00 +00:00
Michael Kret
55df7cbd06
fix(Google Chat Node): Clarify message resource name field (#29964) 2026-05-07 08:16:20 +00:00
Elias Meire
9b3b29b505
fix: Correct connect.html path in browser extension (#29714) 2026-05-07 08:11:53 +00:00
Dawid Myslak
4e2865206c
feat(Formstack Trigger Node): Add webhook request verification (#29495)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 08:07:07 +00:00
Bernhard Wittmann
68560fbb9a
refactor: Extract shared eval helpers (no-changelog) (#29800) 2026-05-07 08:05:01 +00:00
Mutasem Aldmour
34f2107071
feat(core): Accept merge.input(n) inside ifElse/switch branch targets in workflow-sdk (#29716)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jaakko Husso <jaakko@n8n.io>
2026-05-07 07:46:06 +00:00
Mutasem Aldmour
ac993e8859
chore(core): Add CLI to print Instance AI agent prompts (no-changelog) (#29759) 2026-05-07 07:45:49 +00:00
Michael Drury
4b67c31896
feat(core): Add get_environment tool for runtime date and timezone (no-changelog) (#29930)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 07:36:09 +00:00
Dimitri Lavrenük
9255311491
feat: Use agent-browser within Computer Use (no-changelog) (#29863) 2026-05-07 07:27:49 +00:00
Matsu
d247f61096
ci: Flip order of npm releases for idempotency (#29958) 2026-05-07 06:44:17 +00:00
Dawid Myslak
3276edce10
feat(Cal Trigger Node): Add webhook request verification (#29484) 2026-05-07 05:55:23 +00:00
Dawid Myslak
e929f9fbe7
feat(Calendly Trigger Node): Add webhook request verification (#29482) 2026-05-07 05:55:20 +00:00
Dawid Myslak
a772016e36
feat(Customer.io Trigger Node): Add webhook request verification (#29480) 2026-05-07 05:55:17 +00:00
Dawid Myslak
eaadf190b8
feat(Mautic Trigger Node): Add webhook request verification (#29658)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 05:55:10 +00:00
Dawid Myslak
3c97c49d63
feat(Taiga Trigger Node): Add webhook request verification (#29487) 2026-05-07 05:50:38 +00:00
Dawid Myslak
12b7cc6739
feat(MailerLite Trigger Node): Add webhook request verification (#29491)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 05:37:51 +00:00
bjorger
1faa3b1f2a
fix(core): Stop agent builder from hallucinating LLM model ids (no-changelog) (#29922) 2026-05-07 05:11:11 +00:00
Matsu
9d3fb2ba26
ci: Exclude all monorepo packages from safechain minimum age (#29953) 2026-05-07 09:05:22 +03:00
José Braulio González Valido
2164afc5df
chore(ai-builder): Improve eval comparison alert clarity (no-changelog) (#29929)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:20:49 +00:00
Yuliia Pominchuk
dd812c5010
fix(core): Emit missing auth audit events for OIDC and SSO-restricted login (#29856)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-06 19:00:20 +00:00
Stephen Wright
ae57e606b4
fix(core): Initialise encryption key proxy on worker and webhook instances (#29912) 2026-05-06 18:12:48 +00:00
Rob Hough
1e52b14b99
fix(editor-ui): Fix ChatHub prompt background to surface token (no-changelog) (#29892) 2026-05-06 17:47:56 +00:00
Garrit Franke
31f577a39f
feat: Add cred-class-name-suffix lint rule (no-changelog) (#29801) 2026-05-06 16:00:49 +00:00
yehorkardash
64079ad98c
feat(core): Agents as first class entities support (no-changelog) (#28017)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Michael Drury <michael.drury@n8n.io>
Co-authored-by: Arvin A <51036481+DeveloperTheExplorer@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Arvin Ansari <arvin.ansari@n8n.io>
Co-authored-by: bjorger <50590409+bjorger@users.noreply.github.com>
Co-authored-by: Eugene <eugene@n8n.io>
Co-authored-by: Michael Drury <me@michaeldrury.co.uk>
Co-authored-by: Robin Braumann <robin.braumann@n8n.io>
Co-authored-by: Rob Hough <robhough180@gmail.com>
2026-05-06 15:44:44 +00:00
Tuukka Kantola
6b1061386e
feat(editor): Add button to open workflow from Instance AI preview (no-changelog) (#29880)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 14:22:22 +00:00
Itay
bc8d196931
fix(core): Stop logging password reset token values (#29405)
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-05-06 14:02:22 +00:00
Ricardo Espinoza
d6cc3bedd1
feat(core): Add MCP tool to list credentials (#29438) 2026-05-06 13:42:53 +00:00
Ricardo Espinoza
60a51229e0
fix(core): Throw on bare OutputSelector passed to .add()/.to() (#29736) 2026-05-06 13:33:30 +00:00
Andreas Fitzek
04e9b258a8
fix(core): Add support for context establishment hooks in webhook mode (#29893) 2026-05-06 13:22:27 +00:00
Daria
f42be9030e
fix(core): Allow GIT_SSH_COMMAND in simple-git after 3.36.0 upgrade (#29894) 2026-05-06 13:08:25 +00:00
Matsu
de3a98f58f
ci: Apply SafeChain @n8n/* exclusion to all setup-nodejs steps (#29891)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 13:01:53 +00:00
Rob Hough
8e30d78939
refactor(editor): Migrate v2 Dropdown (no-changelog) (#29466) 2026-05-06 12:24:48 +00:00
Alex Grozav
81a621e3d8
refactor(editor): Add injectNDVStore helper and migrate consumers (no-changelog) (#29794) 2026-05-06 12:16:49 +00:00
Michael Kret
35931319b5
fix(Notion Node): Update UI URLs from notion.so to notion.com ahead of domain migration (#29861) 2026-05-06 12:10:45 +00:00
Charlie Kolb
49e7b056b4
fix(editor): Rename canvas header dropdown action to Description (#29719)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 12:04:00 +00:00
Tomi Turtiainen
188ee6d704
chore: Clean up min release age exclude list (no-changelog) (#29882) 2026-05-06 12:01:39 +00:00
Declan Carroll
b6cc694ef5
ci: Exclude @n8n packages from SafeChain minimum package age check (no-changelog) (#29881)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-06 11:53:23 +00:00
Ricardo Espinoza
ed9471a532
fix(ai-builder): Resolve HitlTool variants to base node in get_node_types (#29731) 2026-05-06 11:46:52 +00:00
Daria
bec74aeb4f
fix(core): Add workflow structure validation (#29699) 2026-05-06 11:42:12 +00:00
Daria
d6bae35e8f
fix(editor): Resolve expressions in 'Go to Sub-workflow' navigation (#29843) 2026-05-06 11:41:17 +00:00
Raúl Gómez Morales
a3ae1d8556
fix(editor): Suppress all toasts in Instance AI workflow preview iframe (no-changelog) (#29876) 2026-05-06 11:31:25 +00:00
Garrit Franke
8b54333739
fix(core): Lint package.json in community node tooling (no-changelog) (#29864)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 10:56:31 +00:00
Michael Kret
d63e1ae84e
fix(Google Sheets Node): Reduce duplicate API calls in append operation to avoid quota limits (#29444) 2026-05-06 10:18:18 +00:00
Elias Meire
4dce41f795
feat(core): Transform MCP server configs into dedicated MCP tools (#29493)
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-05-06 10:17:43 +00:00
Jon
4d5bafc146
feat(Jira Node): Add OAuth2 (3LO) support (#29414) 2026-05-06 09:49:30 +00:00
Bernhard Wittmann
b6127d8722
feat: Add fully dynamic disclaimer to Quick Connect offer (#29852) 2026-05-06 09:39:52 +00:00
Garrit Franke
e99e6afb49
feat: Add cred-class-oauth2-naming ESLint rule for community nodes (no-changelog) (#29858)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:37:52 +00:00
Marc Littlemore
ff41613533
fix(editor): Refresh node icon when diff sidebar selection changes (#29816)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 09:23:06 +00:00
Csaba Tuncsik
9afbe13b81
feat(core): Server-side pagination, sorting, and filtering for encryption keys (#29708) 2026-05-06 09:20:14 +00:00
Devendra Reddy Pennabadi
08a36d7515
fix(editor): Preserve decimal suffix when duplicating a node (#29541)
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-05-06 09:13:14 +00:00
mfsiega
f3a21e14a1
chore(core): Scaffold @n8n/engine package (no-changelog) (#29838)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:04:24 +00:00
Suguru Inoue
8aea190659
refactor(editor): Migrate workflow-related workflows store methods (#29853) 2026-05-06 08:54:38 +00:00
Csaba Tuncsik
d4e9705749
test: Add Playwright smoke spec for Vite dev-server boot (#29539) 2026-05-06 08:49:25 +00:00
Garrit Franke
701f9a4627
feat(core): Add n8n-object-validation ESLint rule for community nodes (#29698) 2026-05-06 08:36:53 +00:00
Michael Kret
46d52ffc7e
fix: Handle IMAP fetch errors to prevent instance crash and stuck workflows (#29469) 2026-05-06 08:34:41 +00:00
Iván Ovejero
80c8a6c2fd
fix(core): Fix duplicate task request on runner defer (#28315) 2026-05-06 08:32:48 +00:00
Matsu
61c8895f63
ci: Fix flacky test error assertion (#29848) 2026-05-06 08:31:07 +00:00
Raúl Gómez Morales
f2764f04c0
fix(core): Preserve node positions on AI workflow updates (#29850) 2026-05-06 08:30:10 +00:00
Albert Alises
869dc32c15
feat(ai-builder): Speeds up Instance AI eval by parallelizing iterations and trimming mock handler (no-changelog) (#29839) 2026-05-06 08:15:33 +00:00
Albert Alises
a33a89a215
fix(ai-builder): Allow restoring archived workflows from Instance AI (#29813) 2026-05-06 08:15:16 +00:00
José Braulio González Valido
bbe3e2d148
feat(ai-builder): Add per-PR eval regression detection vs LangSmith baseline (#29456)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:15:08 +00:00
Raúl Gómez Morales
5b01cba8b2
refactor(editor): Extract per-thread runtime from Instance AI store (no-changelog) (#29773) 2026-05-06 08:13:46 +00:00
Andreas Fitzek
2714f00121
fix(core): Allow profile edits when SSO is no longer active (#29765) 2026-05-06 07:59:18 +00:00
Rob Hough
ee847d1624
fix(editor): Fix collapse/expand for Chat sidebar (#29378) 2026-05-06 07:45:51 +00:00
Tomi Turtiainen
b6ee2b93ed
refactor(core): Extract event bus startup recovery helpers (no-changelog) (#29558) 2026-05-06 07:34:12 +00:00
Ali Elkhateeb
07f6de6ba0
refactor(API): Use PublicAPIEndpoint type in all public API handlers (no-changelog) (#29752) 2026-05-06 07:32:52 +00:00
Bernhard Wittmann
57ae85785d
fix: Use /form base URL for Form Trigger production links (no-changelog) (#29766)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-05-06 07:17:56 +00:00
Albert Alises
34b92b1623
fix(core): Add workflow details to builder telemetry (no-changelog) (#29821) 2026-05-06 07:06:04 +00:00
Bernhard Wittmann
50e8218ce8
fix: Replay sub-agent conversation on credential-setup nudge (no-changelog) (#29760) 2026-05-06 06:52:42 +00:00
Garrit Franke
c4056b255e
feat(core): Add no-template-placeholders ESLint rule for community nodes (#29796) 2026-05-06 06:20:37 +00:00
Matsu
5af9d0729f
chore: Bump simple-git to 3.36.0 (#29834) 2026-05-06 06:03:49 +00:00
Jaakko Husso
82354742d3
feat(core): Use McpManagerClient and enforce whether MCP server connections are allowed (#29694)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
CI: Python / Checks (push) Has been cancelled
2026-05-05 17:53:01 +00:00
Albert Alises
4d9e624b41
feat(ai-builder): Guarantee user-visible output on terminal states (#29636) 2026-05-05 16:32:45 +00:00
Konstantin Tieber
283071e611
feat(core): Add flag to import workflow cli to activate workflow on import (#29770) 2026-05-05 16:29:00 +00:00
Iván Ovejero
e2576ca25b
fix(core): Add configurable retries and error details to S3 (#28309) 2026-05-05 15:55:23 +00:00
Jon
4c369e83f2
fix(Snowflake Node): Fix issue with Insert and Update operations not working (#29339)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 15:47:52 +00:00
Benjamin Schroth
bd7eeb7bc8
fix(core): Skip disabled tool nodes when mapping AI Agent tool sources (#29460) 2026-05-05 15:35:13 +00:00
Jon
3a967fc041
chore: Add community PR review skill (no-changelog) (#29626) 2026-05-05 15:25:55 +00:00
Dimitri Lavrenük
ed12bcb58e
feat: Improve computer-use prompt in Instance AI (no-changelog) (#29450) 2026-05-05 14:59:30 +00:00
Matsu
bfc7775ab3
ci: Fix flaky error assertion in tests (#29798) 2026-05-05 14:55:33 +00:00
Matsu
1ca4dd3fa5
ci: Validate required pr quality checks with ci-filter (#29786) 2026-05-05 14:00:45 +00:00
Tomi Turtiainen
e3ff671448
refactor(core): Extract leader election client and improve robustness (no-changelog) (#29696) 2026-05-05 13:44:29 +00:00
Michael Kret
0cafc717a2
fix(Airtable Node): Fix typecast option dropping attachment field updates (#29556) 2026-05-05 13:24:58 +00:00
Ricardo Espinoza
fba873c37e
fix(core): Clarify 0-based indexing in workflow SDK prompts and JSDoc (#29734) 2026-05-05 13:03:47 +00:00
Matsu
c742a85b3b
chore: Update CODEOWNERS to reflect the new group name (#29788) 2026-05-05 12:36:34 +00:00
Declan Carroll
67f621519e
ci: Scope RELEASE env to editor-ui turbo task (no-changelog) (#29585)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 12:21:45 +00:00
Alexander Gekov
d2e1eb30f1
fix(Notion Node): Serialize staticData as ISO string in NotionTrigger (#29688)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 12:18:31 +00:00
Danny Martini
9c4ac76255
fix(core): Log errors from fire-and-forget test webhook deactivation (no-changelog) (#29767) 2026-05-05 12:04:16 +00:00
Iván Ovejero
a7864762ca
fix: Restore broken stdlib calls in Python Code node (#29776) 2026-05-05 11:53:14 +00:00
Charlie Kolb
d5af542f25
fix(editor): Improve sidebar new resource menu UX (#29597)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 11:47:40 +00:00
Matsu
6ace86e0eb
chore: Refactor and add tests for bump-versions.mjs (#29662) 2026-05-05 11:42:10 +00:00
RomanDavydchuk
78aa0e70f2
fix(Supabase Node): Don't display RPCs in an RLC for the table (#28146)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-05-05 11:20:33 +00:00
Raúl Gómez Morales
a408257ebe
fix(editor): Stabilize Instance AI workflow preview rendering (no-changelog) (#29408) 2026-05-05 10:55:33 +00:00
Matsu
ec514da099
ci: Fix race condition between npm releases and daytona snapshots (#29768) 2026-05-05 10:48:46 +00:00
Sudarshan Soma
0697562ac9
fix(Oracle DB Node): Handle the test failures (#28341) 2026-05-05 10:19:14 +00:00
Albert Alises
dc749e0423
refactor(core): Remove global builder node guides (#29582) 2026-05-05 09:27:00 +00:00
Garrit Franke
804f51cf0d
fix(core): Check npm provenance in community package scanner (#29667)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-05 09:26:23 +00:00
n8n-release-tag-merge[bot]
74c256c1c1 Merge tag 'n8n@2.20.0' 2026-05-05 09:42:12 +00:00
n8n-assistant[bot]
b970d259c4
🚀 Release 2.20.0 (#29761)
Co-authored-by: Matsuuu <16068444+Matsuuu@users.noreply.github.com>
2026-05-05 09:14:22 +00:00
Matsu
9ab58df394
chore: Migrate @n8n/nodes-langchain from Jest to Vitest (#28950) 2026-05-05 08:27:59 +00:00
Garrit Franke
4e0f8b5018
feat(core): Add node-operation-error-itemindex ESLint rule (no-changelog) (#29462) 2026-05-05 08:27:04 +00:00
Garrit Franke
c6c6f8ff38
feat: Add valid-credential-references ESLint rule (#29452) 2026-05-05 08:26:50 +00:00
Garrit Franke
8aace75535
feat: Add no-runtime-dependencies ESLint rule (#29366) 2026-05-05 08:26:14 +00:00
Alexander Gekov
0f7776e972
feat(editor): Hide model selector for unsupported AI Gateway actions (#29588)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-05-05 08:14:54 +00:00
Mike Repeć
34c49b9c23
fix(editor): Ignore paste events on read-only canvas (#29673)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 07:51:59 +00:00
Michael Kret
c724dace38
fix: Skip AI tool generation for community trigger nodes (#29453) 2026-05-05 07:50:52 +00:00
Rob Hough
c6cbc49016
refactor(editor): Add motion.scss utilities to standardise animations and transitions (#29704) 2026-05-05 07:34:43 +00:00
Matsu
7c0d3ccb39
ci: Ignore .md & .mdx files on check-pr-size (#29744) 2026-05-05 07:32:48 +00:00
Michael Kret
f401f9101d
fix(Microsoft Outlook Trigger Node): Use per-folder endpoints for folder-scoped message polling (#29663) 2026-05-05 07:07:35 +00:00
Michael Kret
a65e181a22
fix(Postgres Node): Output Large-Format Numbers As option ignored after pool is cached (#29477) 2026-05-05 06:50:35 +00:00
oleg
b41f1a06ab
fix(core): Defer Instance AI temporary workflow cleanup (no-changelog) (#29700)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Create Minor Release PR / Create release PR (push) Has been cancelled
Release: Create Minor Release PR / Notify Slack (push) Has been cancelled
2026-05-04 18:28:27 +00:00
Alex Grozav
17b1206790
refactor(editor): Add executionData store for per-execution state (no-changelog) (#29687)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-05-04 17:22:18 +00:00
moseoh
b72bd1987c
fix(DeepL Node): Update credentials to use header-based authentication (#24614)
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-05-04 17:10:45 +00:00
Andreas Fitzek
4b9e975ca0
feat(editor): Surface cluster information in debug data (no-changelog) (#29583) 2026-05-04 16:27:07 +00:00
Guillaume Jacquart
ad7cdcc04f
feat(core): Add JWE decryption to OAuth2 credential flow (#29497)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 16:14:50 +00:00
Iván Ovejero
568e5a24bf
fix(core): Isolate expressions on chat resumption and test webhook deactivation (#29703) 2026-05-04 15:08:59 +00:00
oleg
96fabbafad
feat(instance-ai): Reuse workflow builder sandboxes (no-changelog) (#29598)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
2026-05-04 14:51:55 +00:00
Jaakko Husso
63d59d48c5
fix(core): Wrap web-search snippets in untrusted data boundaries (no-changelog) (#29695) 2026-05-04 14:19:25 +00:00
Ricardo Espinoza
dad423155f
fix(core): Make MCP client registration cap tunable and surface a proper limit error (#29429) 2026-05-04 13:54:59 +00:00
Mutasem Aldmour
dc6bd68de3
fix(core): Accept placeholder() inside node credentials slot (#29691)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:52:48 +00:00
Daria
1d9548c81f
feat(core): Add MCP tool search executions (#29161) 2026-05-04 13:41:47 +00:00
Jaakko Husso
f69aea3899
refactor(core): Use the common SSRF service on instance AI and harden web fetch (#29674) 2026-05-04 13:37:21 +00:00
Mutasem Aldmour
fdceec21b9
feat: Add pairwise workflow eval pipeline (#29123)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jaakko Husso <jaakko@n8n.io>
2026-05-04 13:26:27 +00:00
Arvin A
4c76aa1467
feat(core): Run evaluation test cases in parallel behind PostHog rollout flag (#29412) 2026-05-04 13:18:01 +00:00
Ali Elkhateeb
e35042999f
fix(core): Add timeout to external secrets provider refresh (#29679) 2026-05-04 13:10:05 +00:00
Andreas Fitzek
45effb8959
feat(core): Add configurable event log path per process (#29403) 2026-05-04 12:49:29 +00:00
Albert Alises
2259f32de8
fix(ai-builder): Add boundaries on the workflow builder remediation loops (#29430) 2026-05-04 12:05:20 +00:00
Alex Grozav
d422d2bafb
refactor(editor): Introduce setter facades for workflow execution state (no-changelog) (#29675) 2026-05-04 11:46:38 +00:00
Michael Kret
62ddc5c443
fix(Compare Datasets Node): Preserve falsy values in mix mode except fields (#29666)
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-05-04 11:42:57 +00:00
Charlie Kolb
9fda7332c4
fix(editor): Make textarea resize handle accessible in NDV (#29676)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 11:35:08 +00:00
Charlie Kolb
f775604c25
refactor: Split up instance-ai confirmation endpoint DTO by action (#29179) 2026-05-04 10:47:38 +00:00
Albert Alises
c28d501ba1
fix(ai-builder): Stop builder from adding auth to inbound trigger nodes by default (#29648) 2026-05-04 10:25:17 +00:00
Alexander Gekov
418f1f2edb
fix(core): Acquire expression isolate for dynamic node parameter requests (#29671)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 10:20:05 +00:00
Albert Alises
dc52bbd532
fix(core): Show AI Builder draft workflows in workflow list (#29670) 2026-05-04 10:15:39 +00:00
Stephen Wright
be22095646
feat(editor): Add reveal redacted data permission to custom roles execution section (#29526) 2026-05-04 09:10:12 +00:00
Luca Mattiazzi
cf8887f9ea
fix(editor): Resolve "Workflow not found" error on evaluations tab (no-changelog) (#29593) 2026-05-04 09:05:10 +00:00
Irénée
baf5bb8e91
refactor: Share SSO provisioning mode types between frontend and backend (no-changelog) (#29384)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Konstantin Tieber <46342664+konstantintieber@users.noreply.github.com>
2026-05-04 08:54:25 +00:00
uppinote
a2afc47c22
feat(editor): Add environment variable to disable workflow autosave (#25144)
Co-authored-by: Daria Staferova <daria.staferova@n8n.io>
2026-05-04 08:33:49 +00:00
Jaakko Husso
595aae498c
fix(editor): Don't paint main sidebar on top of instance AI workflow artifact NDVs (no-changelog) (#29584) 2026-05-04 08:30:39 +00:00
Jean Ibarz
9decb1e2a9
fix(Salesforce Node): Allow overriding JWT audience with My Domain URL (#29016) 2026-05-04 07:53:09 +00:00
Rob Hough
b4d898e4ae
chore: Fix skills so they work with non-Claude harnesses (#29644) 2026-05-04 07:46:03 +00:00
Rob Hough
07b53430f9
feat(editor): Add transition on Sidebar collapsed (#29650) 2026-05-04 07:45:41 +00:00
Tuukka Kantola
8c0faa27c4
feat(editor): Polish Instance AI chat list sidebar (no-changelog) (#29463)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 07:17:47 +00:00
Chris Z
34d7a02df7
fix(core): Reject empty webhookMethods in community lint rule (#29474) 2026-05-04 07:11:24 +00:00
Sandra Zollner
45c18fb09c
feat(core): Decouple insights pruning max age from license (#29527) 2026-05-04 07:03:47 +00:00
n8n-assistant[bot]
88b3a0b3c6
chore: Update node popularity data (#29659)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (beta) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (stable) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (v1) (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-04 01:04:08 +00:00
Charlie Kolb
6bca1fa26f
fix(core): Recreate data table backing tables on entity import (#29454)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 00:31:38 +00:00
Rob Hough
94bf3db438
fix(editor): Use text-color to stop color-scheme override on N8nButton (no-changelog) (#29520)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Lint (push) Has been cancelled
CI: Master (Build, Test, Lint) / Performance (push) Has been cancelled
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Util: Update Node Popularity / approve-and-automerge (push) Has been cancelled
2026-05-02 16:45:15 +00:00
Stephen Wright
243f665e60
fix(editor): Fix OAuth2 credential showing "Needs first setup" after connecting (#29617)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-05-01 12:25:55 +00:00
mfsiega
86f47ee6dc
fix(Schedule Node): Cap day-of-month jitter at 28 (#29614)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:34:37 +00:00
Suguru Inoue
bdf06fa8dd
refactor(editor): Migrate whole workflow object consumers (#29395) 2026-05-01 10:04:55 +00:00
Andreas Fitzek
e17b6864be
feat(core): Add built-in cluster health checks (no-changelog) (#29506)
Co-authored-by: Stephen Wright <sjw948@gmail.com>
2026-05-01 09:28:51 +00:00
Csaba Tuncsik
56412bcce2
fix(editor): Polish encryption keys date range filter (#29569) 2026-05-01 09:03:00 +00:00
Mutasem Aldmour
9b00ccbfd1
fix: Drop template search tools from builder (#29573) 2026-05-01 08:44:21 +00:00
Stephen Wright
ee7260c495
fix(core): Wire EncryptionKeyProxy provider on bootstrap (#29581) 2026-05-01 08:37:38 +00:00
Jon
221c7f7410
fix(Notion Node): Support app.notion.com URL format for page and block ID extraction (#29554)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Build: Benchmark Image / build (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:25:26 +00:00
Stephen Wright
ef3c3e0f80
chore: Upgrade nock to 14.0.13 to fix Node.js 24+ compatibility (#29595) 2026-04-30 15:40:23 +00:00
Rob Hough
6698c42e4e
fix(editor): Add proper bg color for hover state with color-mix() (#29590) 2026-04-30 15:28:15 +00:00
Jaakko Husso
bd130a071f
fix(core): Make instance AI test workflows without publishing them (no-changelog) (#29557)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (beta) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (stable) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (v1) (push) Has been cancelled
2026-04-30 15:04:02 +00:00
Jaakko Husso
b97ca36a99
fix(editor): Make instance ai resource link chips open resources (#29577) 2026-04-30 15:02:03 +00:00
Benjamin Schroth
90d875ce3e
fix(Anthropic Chat Model Node): Add adaptive thinking mode for Claude Opus 4.7+ (#29467) 2026-04-30 13:23:49 +00:00
Mike Repeć
a7ef7416b1
fix(editor): Restore read-only mode for archived workflows on canvas (#29559)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-30 13:22:39 +00:00
Guillaume Jacquart
473d49c9b1
feat(core): Add preAuthentication support to requestOAuth2 pipeline (#29418)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 12:38:03 +00:00
Bernhard Wittmann
12275c86d9
fix(Merge Node): Improve SQL Query mode memory efficiency and error reporting (#28993) 2026-04-30 12:26:38 +00:00
Declan Carroll
c04ea7fae9
ci: Bump safe-chain to v1.5.1 and use safe-mode retry (no-changelog) (#29486)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-30 12:11:35 +00:00
Albert Alises
625ed5e95a
fix(core): Harden Set node workflow SDK contract (#29568) 2026-04-30 12:10:44 +00:00
Albert Alises
661f9908bc
fix(ai-builder): Allow skipping final ask-user question (#29563) 2026-04-30 10:58:45 +00:00
Om Chimurkar
44579d6d3a
fix(editor): Fix sub-workflow folder placement and connection loss (#28770)
Co-authored-by: Charlie Kolb <charlie@n8n.io>
2026-04-30 10:49:02 +00:00
Rob Hough
cdfa7fe4da
refactor(editor): Re-style N8nTooltip (#29509)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-30 10:25:45 +00:00
Garrit Franke
f77dfd1a11
fix(editor): Surface unofficial verified community node tools in AI Tools picker (#28985) 2026-04-30 10:03:47 +00:00
Albert Alises
6175fd6f7b
fix(core): Gate Instance AI edits to pre-existing workflows (#29501) 2026-04-30 08:29:11 +00:00
lif
896461bee3
fix(core): Use editor base URL for workflow and execution links (#23630)
Signed-off-by: majiayu000 <majiayu000@gmail.com>
Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: Matsu <huhta.matias@gmail.com>
2026-04-30 08:25:26 +00:00
Michael Kret
83250c1710
chore: Add tests for SettingsCommunityNodesView (#29461) 2026-04-30 08:17:15 +00:00
Michael Kret
d18f183b21
fix: Allow 5-field cron expressions with step values in polling nodes (#29447)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-30 08:15:37 +00:00
Tomi Turtiainen
8b7b4f575d
fix(core): Handle missing runData during execution recovery (#29513) 2026-04-30 08:12:02 +00:00
José Braulio González Valido
e7f3e6f771
feat(ai-builder): Add three new workflow eval test cases (no-changelog) (#29351)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 08:11:04 +00:00
Alexander Gekov
5799481d1c
fix(Todoist Node): Migrate to Todoist unified API v1 endpoints (#29532) 2026-04-30 08:05:44 +00:00
Csaba Tuncsik
656f9c2d7f
feat(editor): Add data encryption keys settings page (#29068) 2026-04-30 08:02:40 +00:00
Daria
5a56459129
fix(editor): Never block publishing on node execution issues (#29479) 2026-04-30 07:54:43 +00:00
Jon
b2ac67f154
fix(Snowflake Node): Avoid call stack overflow on large result sets (#29200)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 07:53:48 +00:00
Stephen Wright
83c400e8d4
fix(editor): Show permission-aware message on redacted input/output panels (#29521)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-04-30 07:37:29 +00:00
Albert Alises
139b803dae
fix: Use explicit node references for AI memory session keys (#29473) 2026-04-30 07:26:36 +00:00
José Braulio González Valido
4fd68bfc99
ci(ai-builder): Parallelize Instance AI eval CI across multiple n8n containers (#29545)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 07:22:28 +00:00
Tomi Turtiainen
0dbe6c533e
refactor(core): Simplify message event bus recovery (no-changelog) (#29505) 2026-04-30 07:11:09 +00:00
Ali Elkhateeb
74d55b9c68
fix(core): Round fractional time saved values before inserting into insights BIGINT column (#29553) 2026-04-30 07:09:02 +00:00
Jaakko Husso
ef56501d47
fix(core): Force saving executions when instance AI executes WFs (#29515) 2026-04-30 06:47:32 +00:00
Declan Carroll
ab16e197a7
ci: Adjusts Docker builds for Colima compatibility (#29343) 2026-04-30 06:10:27 +00:00
Andreas Fitzek
2a0e2fb47a
fix(core): Restore peer project discovery in share dropdowns (#29537)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-04-29 19:45:07 +00:00
Nikhil Kuriakose
5f93b48e79
feat(editor): Update copy for mcp settings (#29399) 2026-04-29 19:21:04 +00:00
Sandra Zollner
484cb2efba
feat(core): Fix user access control logic (#29481) 2026-04-29 15:42:09 +00:00
Mike Repeć
3791db782b
fix(core): Add missing @n8n/tournament alias to Vite config (no-changelog) (#29530) 2026-04-29 15:25:20 +00:00
Svetoslav Dekov
0e07dedc08
fix: Add sequence prefix to proxy expectation recordings (no-changelog) (#29524) 2026-04-29 15:21:48 +00:00
Iván Ovejero
334ce39f65
test: Retry SSE webhook setup on 404 (#28961)
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 15:15:49 +00:00
Guillaume Jacquart
40da23f688
feat(editor): Track IdP role mapping in provisioning telemetry (#29416)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 15:12:48 +00:00
Alex Grozav
9a91c83a27
refactor(editor): Scope NDV store per workflow document (no-changelog) (#29392) 2026-04-29 15:08:36 +00:00
Jaakko Husso
594c60b497
fix(core): Make instance AI see workflow runtime error messages correctly (no-changelog) (#29371)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Build: Benchmark Image / build (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
2026-04-29 15:06:13 +00:00
Tuukka Kantola
e075f859f9
feat(editor): Add dev-panel for DOM-annotated feedback prompts (no-changelog) (#28761)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 14:42:12 +00:00
Mutasem Aldmour
0a80722dcb
feat: Validate workflow-sdk output topology against mode (#29363)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:39:35 +00:00
Jaakko Husso
388cd79908
fix(core): Pass nodeTypesProvider to validate workflows fully at instance AI (#29333) 2026-04-29 14:25:20 +00:00
Jaakko Husso
84ac8110f8
fix(ai-builder): Handle properties with contradicting displayOptions as OR alternatives instead of AND (#29500) 2026-04-29 14:24:43 +00:00
phyllis-noester
c4bb5ae8df
fix(core): Persist execution context before writing to db (#28973)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:15:13 +00:00
RomanDavydchuk
4358f1d51c
fix(Telegram Trigger Node): Drop pending updates when creating a new webhook (#29103) 2026-04-29 13:57:52 +00:00
Dawid Myslak
1516ec7c06
feat(Netlify Trigger Node): Add webhook request verification (#29256) 2026-04-29 13:45:41 +00:00
Sandra Zollner
898ba5ae25
feat(core): Add migration for postgres variable values (#29489) 2026-04-29 13:45:24 +00:00
Charlie Kolb
d9d1e7c44a
fix(core): Respect global admin scope when listing favorites (#29472)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 13:38:17 +00:00
José Braulio González Valido
54d9286d92
fix(ai-builder): Filter LangSmith eval dataset by local file slugs (#29507)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:30:29 +00:00
Andreas Fitzek
794334cd79
feat: Add instance-level JWKS URI endpoint for JWE public key distribution (#29498) 2026-04-29 13:12:43 +00:00
Rob Hough
758f89c9ef
feat(editor): Move Switch component to core design system (#27322) 2026-04-29 13:11:24 +00:00
Rob Hough
5361257a80
fix(editor): Remove clipping for focus panel textarea (#28677) 2026-04-29 13:11:17 +00:00
Suguru Inoue
39a9ac2a14
refactor(editor): Migrate deprecated workflow-related methods on workflows store (#29362) 2026-04-29 13:04:19 +00:00
Tomi Turtiainen
16d1461858
fix(core): Include stack trace in error logs for non-ApplicationError errors (#29496) 2026-04-29 12:58:56 +00:00
Rob Hough
bc315d087f
fix(editor): Align message box button radius with N8nButton (#29397) 2026-04-29 12:32:08 +00:00
Julian van der Horst
4ea1153dfb
fix: Fix ollama node url path and thinking tokens (#23963)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Dimitri Lavrenük <20122620+dlavrenuek@users.noreply.github.com>
Co-authored-by: Dimitri Lavrenük <dimitri.lavrenuek@n8n.io>
2026-04-29 12:30:03 +00:00
Andreas Fitzek
ec2e2f11dc
feat(core): Add cluster check reconciliation cycle (no-changelog) (#28936) 2026-04-29 12:06:31 +00:00
Stephen Wright
9576ab907c
feat(core): Bootstrap legacy CBC and initial GCM encryption keys on startup (#29400) 2026-04-29 11:50:59 +00:00
Irénée
05e10e2680
feat(core): Manage MCP settings via environment variables (#29368)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 11:29:18 +00:00
Benjamin Schroth
1c8f4ec67b
chore: Update langchain packages (#29342) 2026-04-29 11:23:15 +00:00
Mutasem Aldmour
308d0b42b3
feat(core): Use versioned prebuilt Daytona snapshots for Instance AI sandboxes (#29359)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 11:10:16 +00:00
Tomi Turtiainen
ecd0ba8eba
fix(core): Validate workflow import URL requests (#29178) 2026-04-29 10:52:35 +00:00
Milorad FIlipović
9cb160585c
feat(core): Broadcast workflow settings updates (#29459) 2026-04-29 10:33:53 +00:00
Marc Littlemore
a273a9d3f4
fix(editor): Load more executions on tall screens (#29407)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 10:31:58 +00:00
Jen Y.
d92ec168aa
fix(core): Fix MCP OAuth discovery URL construction and grant type selection (#27283)
Co-authored-by: yehorkardash <yehor.kardash@n8n.io>
2026-04-29 10:21:05 +00:00
Michael Kret
47a6658b2d
fix: Validate sql (#24706) 2026-04-29 10:18:10 +00:00
mfsiega
b8b75719ba
feat(core): Warn and skip on duplicate scheduled executions (#28649)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 10:16:12 +00:00
Mike Repeć
7277566c64
fix(core): Add file path validation to localFile source (#29464) 2026-04-29 10:15:25 +00:00
Declan Carroll
bfc3f88a8b
ci: Fix licensed test filter for fork PR e2e runs (#29451)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 09:24:34 +00:00
Andreas Fitzek
32dd7433b7
fix(core): Correct LDAP search filter construction (#29388) 2026-04-29 09:13:27 +00:00
Ali Elkhateeb
f5132b9e9a
feat(core): Add --include and --exclude flags to import:credentials command (#29364) 2026-04-29 09:08:17 +00:00
Eugene
a4806ce068
chore: Add protect-endpoints skill (no-changelog) (#29385)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 09:02:04 +00:00
Matsu
98e24baf64
chore: Move @n8n/tournament to monorepo (#29358) 2026-04-29 08:32:50 +00:00
Garrit Franke
ca5320a7ed
fix(core): Widen zod peer dependency range in published packages (no-changelog) (#29376) 2026-04-29 08:24:36 +00:00
Stephen Wright
569f94bb82
feat: Include updatedAt in encryption key response DTO (#29424) 2026-04-29 08:16:01 +00:00
oleg
fb65c6155e
fix(core): Generate array types for properties with multipleValues (#29410) 2026-04-29 07:54:15 +00:00
Tomi Turtiainen
328f4b8b96
fix(core): Increase default task runner grant token TTL to 30s (#29443) 2026-04-29 07:43:40 +00:00
Raúl Gómez Morales
e8a79d3f5c
feat(editor): Expand Instance AI agent step timeline by default on cloud (no-changelog) (#29446) 2026-04-29 07:40:18 +00:00
Matsu
b9a8b578c6
chore: Gitignore .claude/worktrees (#29440)
Some checks failed
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
CI: Python / Checks (push) Has been cancelled
2026-04-29 05:48:04 +00:00
Ricardo Espinoza
4ae0322ef2
fix(core): Add GET handler to MCP endpoint for Streamable HTTP spec compliance (#28787) 2026-04-28 22:08:57 +00:00
Ricardo Espinoza
2beb0062a5
fix(editor): Mark workflow dirty after debug pinData changes (#28886) 2026-04-28 22:07:53 +00:00
Declan Carroll
d461ec3e9b
test: Use identity-based assertion in node search test (no-changelog) (#29426)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-28 19:16:30 +00:00
Luca Mattiazzi
ded94a5124
fix(Simple Memory Node): Scope memory nodes session id to single memory node (no-changelog) (#28675) 2026-04-28 16:32:14 +00:00
Bernhard Wittmann
c2749768aa
fix(Google Drive Node): Resolve original file name when copying with empty name (#28896) 2026-04-28 15:13:49 +00:00
oleg
ad359b5e2c
feat(instance-ai): Orchestrator-executed checkpoint tasks for planned workflow verification (#29049)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
2026-04-28 14:58:49 +00:00
Milorad FIlipović
0d907d6794
feat(core): Add endpoint to toggle mcp access for multiple workflows (#29007) 2026-04-28 14:25:39 +00:00
Guillaume Jacquart
e90397627d
feat(core): Add instance-level JWE key infrastructure (no-changelog) (#29071)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 14:25:05 +00:00
Rob Hough
c65fa28e1c
fix(editor): Keep publish actions menu enabled for published workflows (#29396) 2026-04-28 13:56:35 +00:00
Alex Grozav
39154b9037
refactor(editor): Move node issues to workflow document store (no-changelog) (#29390) 2026-04-28 13:53:59 +00:00
Bernhard Wittmann
e04f027b5d
fix(Zammad Node): Add To and CC fields for email articles (#28860) 2026-04-28 13:16:45 +00:00
Jon
aa0daf9fb6
feat(Slack Node): Allow users to configure OAuth2 scopes (#28728)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:30:40 +00:00
Iván Ovejero
7722023abd
fix(core): Reset Redis retry counter on successful reconnect (#29377) 2026-04-28 12:07:54 +00:00
Guillaume Jacquart
8551b1b90c
fix(core): Apply credential allowed domains in declarative node requests (#29082)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 12:04:27 +00:00
Tomi Turtiainen
3f350a8577
fix(core): Make task runner grant token TTL configurable (#29357) 2026-04-28 12:04:02 +00:00
Declan Carroll
16a36186f2
ci: Tighten n8n testcontainer wait strategy and add sequential service start (#29352)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 11:36:03 +00:00
Tomi Turtiainen
7bd3532f07
fix(core): Fix code node executions hanging when idle timer overlaps with task acceptance (#29239) 2026-04-28 11:07:43 +00:00
n8n-release-tag-merge[bot]
d6618f3c68 Merge tag 'n8n@2.19.0' 2026-04-28 10:25:56 +00:00
Rob Hough
d332fe9c84
refactor(editor): Align @n8n/design-system with DS3 (no-changelog) (#28428) 2026-04-28 09:53:05 +00:00
Michael Kret
47ad39777f
fix: No Credits state for n8n Connect badge (#29375) 2026-04-28 09:47:36 +00:00
Stephen Wright
258b9703c5
refactor: Migrate all cipher call sites to encryptV2/decryptV2 (#29096) 2026-04-28 09:24:01 +00:00
n8n-assistant[bot]
632604bbe3
🚀 Release 2.19.0 (#29374)
Co-authored-by: Matsuuu <16068444+Matsuuu@users.noreply.github.com>
2026-04-28 09:23:10 +00:00
Matsu
6ec8144914
chore: Enable OxLint in editor-ui (#29360) 2026-04-28 09:22:05 +00:00
Suguru Inoue
eb053180b0
refactor(editor): Migrate allNodes in workflow store (#29070) 2026-04-28 09:11:32 +00:00
Dimitri Lavrenük
2171e9461f
fix: Remove serve mode from computer-use (no-changelog) (#29102)
Co-authored-by: Elias Meire <elias@meire.dev>
2026-04-28 08:31:18 +00:00
Andreas Fitzek
a70a31411d
feat(core): Remove expression role mapping feature flag (#29361) 2026-04-28 08:31:14 +00:00
Joco-95
8f16999516
fix: Fixes redirect bug on AI Assistant caused by settings evaluation sync issue (no-changelog) (#29348) 2026-04-28 08:14:06 +00:00
Joco-95
10f619f6d6
fix: Fixes AI Assistant opt-in modal terms link (#28779) 2026-04-28 08:13:48 +00:00
Declan Carroll
95a626350a
test(editor): Remove dead code and reclassify utility page objects in Playwright (no-changelog) (#28992)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-28 08:11:20 +00:00
Luka Zivkovic
13029e6d03
fix(ai-builder): Keep workflow identity across rebuild/patch (#28926)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 08:03:43 +00:00
Raúl Gómez Morales
3a468c2b73
feat(editor): Stream Instance AI builders at conversation bottom and fix iframe resize (no-changelog) (#29332) 2026-04-28 07:53:00 +00:00
Matsu
4cf26bb70b
ci: Clean up Template Injection surface in Actions (#29354) 2026-04-28 07:44:44 +00:00
José Braulio González Valido
ffef9c9c48
fix(core): Retry Phase 1 hint generation when triggerContent is empty (no-changelog) (#29109)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 07:26:25 +00:00
José Braulio González Valido
e503587854
docs: Restructure instanceAI evals README for first-time users (no-changelog) (#29095)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 07:22:45 +00:00
Bernhard Wittmann
3409a67dfe
fix(Microsoft Outlook Trigger Node): Show nested subfolders in folder dropdowns (#28759) 2026-04-28 07:18:43 +00:00
Julian van der Horst
c7a0f3eb39
feat(Salesforce Node): Add middle name, suffix, and identity fields to contacts (#23905)
Co-authored-by: yehorkardash <yehor.kardash@n8n.io>
2026-04-28 07:07:10 +00:00
Jaakko Husso
b6fcabc025
fix(ai-builder): Adjust chat trigger memory builderHints (#29156) 2026-04-28 07:06:53 +00:00
Garrit Franke
fadd81c519
feat(core): Add valid-peer-dependencies ESLint rule for community nodes (no-changelog) (#28983)
Co-authored-by: Garrit Franke <garritfra@users.noreply.github.com>
2026-04-28 06:59:21 +00:00
Jaakko Husso
a7d7352c9b
feat(core): Drop BetaTag from sidebar, use 'Preview' instead for new features (#29347) 2026-04-28 06:35:58 +00:00
Charlie Kolb
98ec56ad77
feat(editor): Add Delete permanently link to workflow archive toast (#29157) 2026-04-28 06:32:12 +00:00
Srinjoy
048e01e060
fix: Preserve structuredContent in MCP nodes to prevent AI Agent reasoning loops (#27297)
Co-authored-by: Bernhard Wittmann <bernhard.wittmann@n8n.io>
2026-04-28 06:28:38 +00:00
krisn0x
58d79832bc
fix(Gmail Trigger Node): Exclude scheduled emails from trigger query (#29244) 2026-04-28 06:17:12 +00:00
José Braulio González Valido
6daccce97c
fix(core): Fix credential mocking in eval mode for multi-auth nodes (no-changelog) (#29094)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:06:28 +00:00
Luka Zivkovic
4deb356a51
test(editor): Make instance AI partial-apply test deterministic (no-changelog) (#29248)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 19:55:57 +00:00
RomanDavydchuk
0aabee0a99
fix(Google Gemini Node): Filter out undefined parts when processing API responses (#28567)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-04-27 15:58:50 +00:00
krisn0x
65e55a88c1
fix: Allow task runner to invoke skills via slash command prefix (#29302)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:42:25 +00:00
Albert Alises
632ae67de3
fix(ai-builder): Hide and reap intermediate AI-created workflows (#29066) 2026-04-27 15:17:54 +00:00
Jon
90843cf4ba
feat(Slack Node): Add emoji reaction filter to Slack Trigger (#28628)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:04:56 +00:00
Albert Alises
dc33223d3b
fix(editor): Show error toasts in Instance AI executable canvas (#29328) 2026-04-27 14:57:06 +00:00
Bernhard Wittmann
0a89814220
fix(core): Update local gateway Electron packaging dependencies (no-changelog) (#29336) 2026-04-27 14:49:39 +00:00
Alex Grozav
e028204c56
refactor(editor): Provide workflow id and document store at app root (no-changelog) (#29297) 2026-04-27 14:37:07 +00:00
Ali Elkhateeb
2d721d29f3
feat(core): Add --projectId filter to export:workflow and export:credentials commands (#29329) 2026-04-27 14:24:12 +00:00
Matsu
370b281216
chore(core): Enable TypeScript strict mode in packages/cli (no-changelog) (#27876)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:21:31 +00:00
Konstantin Tieber
553976d065
fix(core): Workflow import cli doesn't deregister crons for deactivated workflows (#29129) 2026-04-27 14:19:47 +00:00
Charlie Kolb
b71a31d2a9
fix(editor): Constrain InstanceAiView stacking context below sidebar (#29324)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:00:19 +00:00
mfsiega
acd18ef9e9
feat(Schedule Node): Emit deduplication key when enabled (no-changelog) (#28646)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:55:15 +00:00
Jaakko Husso
97bdbd055a
fix(ai-builder): Validate required inputs on AI nodes (#29159) 2026-04-27 13:47:47 +00:00
oleg
3a9c922bf4
fix(instance-ai): Make SANDBOX_LINK_SDK flag bypass Dockerfile SDK install (no-changelog) (#29207) 2026-04-27 13:42:48 +00:00
Alexander Gekov
5f2c32ad6e
feat(OpenAI Node): Use dynamic model selection for image edit and update analyze model filter (#29223)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-04-27 13:28:49 +00:00
Ali Elkhateeb
b4373715f3
feat(core): Add PATCH endpoint for data table column management (#29090) 2026-04-27 12:53:02 +00:00
Daria
23170e436a
fix(editor): Disable WF version menu only when all actions are unavailable (#29266) 2026-04-27 12:50:57 +00:00
José Braulio González Valido
29cdd011b0
fix(ai-builder): Honor --timeout-ms across the eval harness (no-changelog) (#29219)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 12:49:01 +00:00
Ricardo Espinoza
19b2388aca
fix(core): Pass userId through webhook test execution path for redaction (#28775) 2026-04-27 12:46:38 +00:00
Suguru Inoue
cf5cdbfbcf
fix(editor): Populate chat history in executions view (#29229) 2026-04-27 12:33:18 +00:00
RomanDavydchuk
20d9215736
fix(editor): Copy to editor not using pinned data from the execution (#28905)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-04-27 12:31:36 +00:00
Matsu
3637287ee1
chore: Prepare tsconfigs for tsgo (#29230) 2026-04-27 12:30:22 +00:00
Declan Carroll
bb0a550039
test: Surface container logs on postgres/redis startup failure (#29017)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 12:14:40 +00:00
Stephen Wright
641d492d56
feat(core): Wire Cipher to encryption key proxy for key rotation support (#29013) 2026-04-27 12:09:04 +00:00
Ricardo Espinoza
0eb30c6ca7
fix(editor): Fix column collapse button not visible in table view (#28899) 2026-04-27 11:43:21 +00:00
Irénée
ff6d65e22a
feat: Enable log streamin settings via env vars (#29005) 2026-04-27 11:39:42 +00:00
Romeo Balta
905f3eb4be
feat(editor): Add resource center experiment (no-changelog) (#28906)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
2026-04-27 11:34:25 +00:00
Andreas Fitzek
b2b1370e5d
fix(core): Harden event log parse against malformed input (#29004) 2026-04-27 09:27:52 +00:00
Jon
e4004fa26a
chore: Deprecate SerpAPI tool node in favour of official verified node (#28829) 2026-04-27 09:13:53 +00:00
Michael Kret
f6582783ea
feat: In the n8n Connect table on row click open execution related to that usage row (#29075)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-27 09:03:17 +00:00
José Braulio González Valido
250b718936
fix(ai-builder): Stop tombstoning example UUIDs in LangSmith dataset sync (no-changelog) (#29112)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 08:52:17 +00:00
Marc Littlemore
1256da91f0
fix(core): Persist execution metadata for failed executions in scaling mode (#28774)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 08:27:45 +00:00
Sandra Zollner
2b0add185f
feat(core): Add public API endpoints for data table column management… (#29073)
Co-authored-by: Ali Elkhateeb <ali.elkhateeb@n8n.io>
2026-04-27 08:22:19 +00:00
Mutasem Aldmour
b44e9d1207
fix(core): Allow .trim() in workflow-sdk parsing and coerce stringified patches (#29111)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 08:17:22 +00:00
Michael Kret
d2d7dfc276
feat: Add warning when publishing workflow, if some nodes in it are using ai gateway credentials (#29089) 2026-04-27 08:14:31 +00:00
Declan Carroll
b37044e124
fix(core): Upgrade task-runner-launcher to v1.4.5 (#29155)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 08:03:01 +00:00
Bernhard Wittmann
5cef66269e
fix(WooCommerce Trigger Node): Guard HMAC verification against missing secret (#28964) 2026-04-27 07:55:42 +00:00
Iván Ovejero
494a855d34
fix(core): Prevent Redis connection recovery from being missed (#28256) 2026-04-27 07:38:57 +00:00
phyllis-noester
b1ddbf26b0
fix(editor): Allow users to logout of dynamic creds in chathub (#29117) 2026-04-27 07:27:14 +00:00
Andreas Fitzek
1d325a20ca
feat(core): Accept token-exchanged scoped JWTs on the instance MCP server (#28909) 2026-04-27 07:22:29 +00:00
Michael Kret
b0ec5cdb69
fix(Google Gemini Node): Show Number of Images option only for models that supports it (#29153) 2026-04-27 07:22:04 +00:00
Abhishek Deshmukh
1e77f7146d
fix(core): Add missing break statements in filter condition evaluation (#27708)
Co-authored-by: Bernhard Wittmann <bernhard.wittmann@n8n.io>
2026-04-27 06:08:25 +00:00
Bernhard Wittmann
67af2e177d
feat(core): Add opt-in RFC-style outbound User-Agent via env flag (#28771)
Co-authored-by: Muhammad Osama <muhammadosama984@gmail.com>
2026-04-27 06:01:09 +00:00
n8n-assistant[bot]
380866838e
chore: Update node popularity data (#28379)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-27 01:17:55 +00:00
aikido-autofix[bot]
35449aaa7b
fix: Fix 11 security issues in @xmldom/xmldom, defu, @langchain/community and 5 more (#29126)
Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
2026-04-25 07:19:12 +00:00
James Gee
9599fb9d54
feat(core): OTEL changes to support context propagation (#28720)
Co-authored-by: konstantintieber <konstantin.tieber@n8n.io>
2026-04-24 16:42:48 +00:00
Jaakko Husso
f27bbc9022
fix(core): Improve title generation on instance AI threads (no-changelog) (#29084) 2026-04-24 15:55:13 +00:00
Jaakko Husso
bc5e490f68
fix(ai-builder): Support 'disabledOptions' in node schemas (#28894) 2026-04-24 15:54:12 +00:00
Bernhard Wittmann
5dda3b2142
fix(GitHub Node): Return pagination token as string in resource locators (#29099)
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-04-24 15:39:44 +00:00
Albert Alises
0d16dd5dfb
fix(core): Surface credential and resource choice when more than one match exists (#29087) 2026-04-24 15:21:05 +00:00
Iván Ovejero
481fbdf186
fix(core): Prevent S3 socket pool exhaustion on partial stream reads (#28313) 2026-04-24 14:51:44 +00:00
mfsiega
875d9c980c
feat(core): Add deduplicationKey column to execution entity (no-changelog) (#28645)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 14:47:58 +00:00
Milorad FIlipović
e183ae4434
fix(core): Broadcast MCP availability change via push connection (#29019) 2026-04-24 14:35:36 +00:00
Elias Meire
47bb91e9b4
feat(editor): Move computer use toggle to chat sidebar (#28974)
Co-authored-by: Dimitri Lavrenük <20122620+dlavrenuek@users.noreply.github.com>
2026-04-24 14:32:02 +00:00
Iván Ovejero
f3efcf8a54
feat(core): Add observability for the VM expression engine (#28715)
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 14:11:07 +00:00
Declan Carroll
147bd8c84f
fix(core): Pin Alpine version in Docker builder stages for reproducible builds (#29097)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 13:53:00 +00:00
Nihaal Sangha
a9e5f0ea48
fix(Schedule Node): Avoid using 0 day of month (#28432) 2026-04-24 13:52:11 +00:00
Gauthier POGAM--LE MONTAGNER
11ebf61471
feat(Postgres Node): Sort PostgreSQL schemas and tables alphabetically when fetching (#28036)
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-04-24 13:50:17 +00:00
Albert Alises
9345d132fa
fix(core): Surface pagination state in instance AI credentials list (#29098) 2026-04-24 13:45:13 +00:00
Cocoon-Break
b143830f24
fix: Correct typo in proxy error message: not value -> not valid (#28318)
Signed-off-by: Cocoon-Break <54054995+kuishou68@users.noreply.github.com>
2026-04-24 13:33:13 +00:00
JUNG SEUNGHOON
abd6eacce8
docs: Fix frontend package links in contributing guide (#27727)
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-04-24 13:28:52 +00:00
Pedro Dicati
80cb82e9c5
feat(Google Drive Node): Add Markdown export option for Google Docs download (#27006)
Co-authored-by: Pedro Dicati <pedro.dicati@cognitivo.ai>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Elias Meire <elias@meire.dev>
2026-04-24 13:27:30 +00:00
Alex Grozav
c1769268ef
refactor(editor): Move workflow serialization to workflowDocument store (#28945) 2026-04-24 13:23:43 +00:00
Mutasem Aldmour
e1295187f1
feat(core): Stamp x-n8n-feature on proxied LLM calls for cost attribution (#28987)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:17:49 +00:00
Jaakko Husso
afe4298427
fix(ai-builder): Improve button, icon, callout and workflowSelector schemas (#28828)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 13:10:14 +00:00
patdt
af3841f629
feat(core): Add instance setting to disable public chat in Chat Trigger (#27565)
Co-authored-by: jeanpaul <jeanpaul@users.noreply.github.com>
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-04-24 12:56:40 +00:00
Yuval Dinodia
0f4c5b396d
fix(core): Improve error messages for invalid node and trigger input (#28053)
Co-authored-by: Declan Carroll <declan@n8n.io>
Co-authored-by: Milorad FIlipović <milorad@n8n.io>
2026-04-24 12:24:01 +00:00
Jaakko Husso
3a8239e52b
fix(core): Make instance AI prefer newer AI models (no-changelog) (#29028) 2026-04-24 12:21:02 +00:00
Cj Fraser
7f54ff4acf
fix(Xero Node): Update OAuth Scopes to meet new Xero API requirements (#27563)
Co-authored-by: Garrit Franke <garrit.franke@n8n.io>
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
Co-authored-by: Dimitri Lavrenük <20122620+dlavrenuek@users.noreply.github.com>
2026-04-24 11:40:29 +00:00
Johan Hedin
cc2d4da0c9
chore(Ollama Chat Model Node): Update @langchain/ollama to 1.0.3 to for separation of thinking (#23098)
Co-authored-by: Johan Hedin <johan.hedin@omda.com>
Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
2026-04-24 11:38:08 +00:00
Albert Alises
e10509f114
fix(editor): Align Model and Sandbox visibility with edit permissions (#29076) 2026-04-24 11:13:43 +00:00
Suguru Inoue
39dcab4b47
refactor(editor): Migrate or cleanup workflow-dependent methods in workflows store (#29006) 2026-04-24 11:12:39 +00:00
Sandra Zollner
fda3d5cf8d
feat(core): Add public API endpoints for folder management (folderId) (#28790) 2026-04-24 11:10:28 +00:00
md
3c54cda575
fix(editor): Checklist not showing workflow settings configuration (#28034)
Co-authored-by: Alex Grozav <alex@grozav.com>
2026-04-24 11:08:43 +00:00
Bernhard Wittmann
bb25d4cc38
fix(core): Scope live and test webhook handlers to their route family (#28804) 2026-04-24 11:06:02 +00:00
Bernhard Wittmann
089d6bda0e
fix(Discord Node): Correctly handle API rate limits (#29051) 2026-04-24 11:05:43 +00:00
Dawid Myslak
7fd0b3761d
fix(editor): Refresh wallet balance when usage refresh is clicked (#29067) 2026-04-24 10:41:25 +00:00
Garrit Franke
ef944b4a52
fix(editor): Show Manage community-node link to admins, not just owners (#29060) 2026-04-24 10:19:05 +00:00
Raúl Gómez Morales
e77eb1870b
feat(editor): Upgrade Instance AI artifact preview tabs (no-changelog) (#28997) 2026-04-24 10:15:50 +00:00
Matsu
0f7a048b37
ci: Change token used for dist-tag updates (#29072) 2026-04-24 10:05:36 +00:00
Albert Alises
0c5d82ad2c
test(core): Re-record instance-ai workflow-setup-actions expectations (no-changelog) (#29069) 2026-04-24 09:58:15 +00:00
José Braulio González Valido
540faa7c1d
fix(ai-builder): Update eval dataset prompts to match scenario checklists (no-changelog) (#29011)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:55:18 +00:00
oleg
9ea8533873
fix(core): Pin sandbox workflow-sdk to host version (#29048) 2026-04-24 09:40:49 +00:00
renovate[bot]
f9035b4c1b
chore: Update zod to 3.25.76 [SECURITY] (#28553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-24 09:29:46 +00:00
Declan Carroll
330211c5ae
fix(editor): Surface configured minimum password length in UI (#28194)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 09:05:57 +00:00
Charlie Kolb
390b963e29
fix(editor): Address design feedback for favoriting (no-changelog) (#28523) 2026-04-24 08:36:38 +00:00
mfsiega
781b6b5392
feat(core): Add scheduled execution deduplication flag (no-changelog) (#28642) 2026-04-24 08:27:47 +00:00
Sandra Zollner
9e694f5f41
feat(core): Centralise user listing permissions for internal and publ… (#28989) 2026-04-24 08:08:35 +00:00
Dimitri Lavrenük
81dbb16043
fix: Fix computer use deny button size (no-changelog) (#28903) 2026-04-24 07:56:11 +00:00
Benjamin Schroth
c961849226
feat(ai-builder): Add sub-agent evaluation harness with binary checks (no-changelog) (#28289)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 07:50:46 +00:00
Dimitri Lavrenük
ccbd914594
fix(MySql Node): Fix table name filtering (#28911) 2026-04-24 07:44:08 +00:00
Michael Kret
67bd8de90f
fix: Disable "Get 100 free OpenAI API credits"  if aiGateway enabled in the license (#29050) 2026-04-24 07:35:16 +00:00
yehorkardash
68c289f76f
fix: Use different runtime for each agent call, refactor state management (#27915) 2026-04-24 07:22:38 +00:00
Declan Carroll
20d8e90c95
ci: Refactor and optimizes E2E test runs in CI (#28968)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:09:32 +00:00
Albert Alises
8b33424d0f
fix(ai-builder): Stop treating empty defaults as satisfying required for the Split node (#28978) 2026-04-23 16:22:19 +00:00
aikido-autofix[bot]
6650068f00
fix: Fix 15 critical issues in protobufjs, defu, @langchain/community and 6 more (#28661)
Co-authored-by: Declan Carroll <declan@n8n.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 15:25:18 +00:00
Guillaume Jacquart
6d1989449d
fix(core): Use leaf-level scope check for OAuth2 cleanup (no-changelog) (#28953)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 15:06:43 +00:00
Dimitri Lavrenük
b649eea01d
fix(EditImage Node): Fix orientation when modifying images (#28970)
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-04-23 14:02:43 +00:00
Michael Kret
222fce3364
chore: Add ai_gateway_credentials flag to nodes graph (#28971) 2026-04-23 13:50:16 +00:00
José Braulio González Valido
720fa753cd
fix(core): Honor request encoding when shaping eval mock HTTP responses (no-changelog) (#28976)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:44:05 +00:00
Guillaume Jacquart
5af4e1cc19
feat(API): Add encryption key management endpoints (#28897)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 13:27:57 +00:00
Ali Elkhateeb
f931b17a93
feat(core): Add delete folder endpoint to public API (#28984)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-23 13:13:13 +00:00
Dimitri Lavrenük
71b2b88eb8
fix: Correctly rename all temporal binary files after execution (#28960) 2026-04-23 13:02:41 +00:00
Suguru Inoue
9415f441d9
refactor(editor): Migrate deprecated methods in useWorkflowState (#28672) 2026-04-23 12:14:42 +00:00
Dawid Myslak
3a165d4843
feat(Alibaba Cloud Node): Switch to dynamic model list fetched from API (#28839) 2026-04-23 12:08:34 +00:00
Matsu
a2ff55c1f9
chore: Reuse ts-morph Project instance across custom template run (no-changelog) (#28972)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 11:23:18 +00:00
Matsu
af25a0e7eb
ci: Fix urlencoding in set-latest ci script (#28965) 2026-04-23 11:22:08 +00:00
Alex Grozav
9997203667
refactor(editor): Use workflowsStore.workflowId computed shorthand (no-changelog) (#28851) 2026-04-23 11:19:04 +00:00
José Braulio González Valido
89e9117d39
fix(ai-builder): Expose outputCount when eval node output is truncated (no-changelog) (#28977)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:06:27 +00:00
oleg
7a64bd23d7
test(instance-ai): add memory benchmark harness with heap snapshot analysis (no-changelog) (#27972)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
2026-04-23 10:36:02 +00:00
Mutasem Aldmour
09d4756ef3
feat(core): Annotate LangSmith traces with user feedback from Instance AI (no-changelog) (#28874)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:31:52 +00:00
Csaba Tuncsik
c662862d7f
fix(core): Clean up project mapping rules on provisioning strategy switch (#28726) 2026-04-23 10:29:14 +00:00
RomanDavydchuk
7e3a2f6885
fix(core): Can't install community nodes on Windows (#28481)
Co-authored-by: Shireen Missi <94372015+ShireenMissi@users.noreply.github.com>
2026-04-23 10:06:31 +00:00
RomanDavydchuk
f2aa0160af
fix(Jenkins Node): Properly load job parameters (#28631) 2026-04-23 09:59:13 +00:00
Declan Carroll
886f22ee6d
chore: Add code-health baseline and fix janitor catalog violation (no-changelog) (#28958)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 09:55:55 +00:00
Garrit Franke
76a558f550
feat(core): Add webhook-lifecycle-complete ESLint rule for community nodes (no-changelog) (#28778) 2026-04-23 09:28:09 +00:00
Jon
13dbcf9bbb
feat(AwsS3 Node): Add option to return common prefixes in bucket search (#28571)
Co-authored-by: Elias Meire <elias@meire.dev>
2026-04-23 09:12:36 +00:00
Matsu
fd000edf1c
fix(editor): Fix flaky SQL completions for quoted identifiers in mixed language parser (no-changelog) (#28957)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 09:03:44 +00:00
Matsu
9abaea8518
chore: Migrate @testing-library/jest-dom to support Vitest in @n8n/composables (#28389) 2026-04-23 08:51:54 +00:00
Csaba Tuncsik
c55b95ff06
fix(core): Shift existing rules on create to avoid order conflict (#28722) 2026-04-23 08:50:55 +00:00
Ali Elkhateeb
a757ddd4a8
fix(core): Support mixed bracket/dot notation in external secrets expressions (#28711)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 08:48:57 +00:00
José Braulio González Valido
16e5f9572f
feat(ai-builder): Add LangSmith integration for workflow eval tracking (no-changelog) (#28835)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:47:02 +00:00
Garrit Franke
639e1dab1c
chore(Anthropic Chat Model Node): Update default model to Claude Sonnet 4.6 (#28864) 2026-04-23 08:41:55 +00:00
Garrit Franke
3f9464f7b7
feat(core): Add no-overrides-field ESLint rule for community nodes (no-changelog) (#28944) 2026-04-23 08:40:43 +00:00
Andreas Fitzek
d8a951dee8
test(core): Add instance registry schema and cluster membership tests (no-changelog) (#28723) 2026-04-23 08:26:13 +00:00
Jaakko Husso
5fa1f8f7d9
fix(core): Preserve user-selected credentials when AI recreates a node (#28943) 2026-04-23 08:24:23 +00:00
Dawid Myslak
1c52b0a448
fix(Moonshot Kimi Node): Update default model to kimi-k2.6 (#28859) 2026-04-23 08:08:11 +00:00
Elias Meire
4352749ec9
fix(editor): Save button never shows saved state after saving credentials (#28486) 2026-04-23 07:59:45 +00:00
Csaba Tuncsik
e25a78e346
fix(core)!: Unify role mapping feature flag across backend and frontend (#28718) 2026-04-23 07:48:52 +00:00
Konstantin Tieber
bb6a5e47b0
feat(core): Add audit logs for webhook waiting and resuming (#28204) 2026-04-23 07:43:43 +00:00
Bernhard Wittmann
a2aa69dbd7
fix: Add credential auth and test for Twilio, Pipedrive, Asana, Freshdesk, Workable (#28265) 2026-04-23 07:41:36 +00:00
Sandra Zollner
1eea62629a
fix(core): Fixes user search functionality in ProjectSettings for pr… (#28914) 2026-04-23 07:38:03 +00:00
Iván Ovejero
bce5c9a103
chore: Move @n8n/tournament to catalog and bump to 1.0.7 (#28890) 2026-04-23 07:35:59 +00:00
Andreas Fitzek
0c021116bc
feat(core): Add AES-256-GCM cipher support (#28916) 2026-04-23 07:31:37 +00:00
Declan Carroll
a31d003c05
ci: Centralize CI Docker image build and distribution (#28798)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:18:52 +00:00
oleg
7a47fddd90
refactor(ai-builder): Streamline instance-ai prompt surface (no-changelog) (#28754) 2026-04-23 07:05:57 +00:00
Albert Alises
516d181b10
test(core): Add E2E coverage for Instance AI workflow setup apply actions (no-changelog) (#28907) 2026-04-23 07:03:56 +00:00
Declan Carroll
c4ff0188db
fix: Update hono, protobufjs, yaml, and other dependencies (#28877)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 06:54:57 +00:00
Markus Corazzione
5ee534c3b8
fix(core): Preserve manual scopes for inherited generic OAuth2 credentials (#27858)
Co-authored-by: Guillaume Jacquart <jacquart.guillaume@gmail.com>
2026-04-23 06:54:25 +00:00
Guillaume Jacquart
828d0ee906
fix(core): Allow SAML connection test without saving config first (#28702)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 06:53:06 +00:00
Stephen Wright
1b02a0dbf4
fix: Disable until we encrypt (#28875) 2026-04-23 06:43:22 +00:00
Charlie Kolb
e62e44f3f8
feat(editor): Warn when data table cell value exceeds safe integer range (#28904)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 06:35:15 +00:00
Michael Kret
46739a5bc4
feat(Google Gemini Node): Gemini default models update (#28853) 2026-04-23 06:33:51 +00:00
Bernhard Wittmann
7d6f777808
fix(Brevo Node): Send valid email attachments with correct filenames (#28816) 2026-04-23 06:27:10 +00:00
Marcus
4ce186a14d
fix(core): Request helper function support setting agentOptions (#28756)
Co-authored-by: Elias Meire <elias@meire.dev>
2026-04-23 06:06:27 +00:00
Bernhard Wittmann
7be9f65399
fix(RabbitMQ Trigger Node): Redeliver messages on failed executions (#28712) 2026-04-23 05:59:46 +00:00
Albert Alises
d58e67e76e
feat(core): Guard Instance AI prompts against asking for plaintext secrets (#28876) 2026-04-22 20:26:21 +00:00
Jean Ibarz
41424b3e99
fix(core): Declare credentialType on MCP workflow-builder autoAssignedCredentials schema (#28353) 2026-04-22 19:53:19 +00:00
Matsu
50dab4663a
ci: Use npm registry HTTP API for dist-tag promotion (no-changelog) (#28898)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 08:29:51 +03:00
Sandra Zollner
ff9d7d6756
feat(core): Add public API endpoints for folder management (#28760) 2026-04-22 12:21:53 +00:00
Alex Grozav
6e131fb206
refactor(editor): Add hydrate and reset to workflow document store (#28786) 2026-04-22 12:18:00 +00:00
Andreas Fitzek
d49049dd3f
fix: E2E test for token exchange (#28895) 2026-04-22 11:44:02 +00:00
Declan Carroll
c8bdd26100
test: Enhance test discovery to support dynamic titles (#28782) 2026-04-22 11:33:09 +00:00
Bernhard Wittmann
b9c4618270
fix(Gmail Trigger Node): Add maxResults limit to prevent OOM on large inboxes (#28470) 2026-04-22 11:20:28 +00:00
Matsu
571388924d
ci: Add explicit registry scope for @n8n packages in dist-tag workflow (no-changelog) (#28889)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 10:57:23 +00:00
Daria
b6eabb4ce5
fix(core): Fix health endpoint cross-origin requests (#28878) 2026-04-22 10:55:34 +00:00
Milorad FIlipović
2c60f42fd0
fix(editor): Update oAuth consent screen copy (no-changelog) (#28870)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-22 10:23:56 +00:00
bjorger
2bd8b47207
fix(editor): Prevent executions table flicker on empty auto-refresh (#28805) 2026-04-22 10:01:33 +00:00
Andreas Fitzek
f2f76d0ebd
feat(core): Expose instance registry via proxy service (no-changelog) (#28691) 2026-04-22 10:00:24 +00:00
Guillaume Jacquart
c40599b82e
feat(core): Add encryptWithKey and decryptWithKey to Cipher service (#28608)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 09:59:41 +00:00
Milorad FIlipović
c9aa5fca84
fix(core): Emit modern error connections from SDK (no-changelog) (#28700) 2026-04-22 09:32:13 +00:00
Andreas Fitzek
fd124420f1
test(core): Add E2E tests for token exchange delegation flow (#28434) 2026-04-22 09:31:19 +00:00
Jaakko Husso
8630845cbd
fix(core): Fix fixedCollection validation issues and empty setup cards on instance AI (#28794)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 08:53:10 +00:00
Bernhard Wittmann
d8f742baa6
fix(editor): Show saved credentials when node has mismatched credentials object (#28693) 2026-04-22 08:35:32 +00:00
Dimitri Lavrenük
d3ef7e3e0f
fix(Discord Node): Fix file name and mimetype for file upload (#28807) 2026-04-22 08:14:57 +00:00
Guillaume Jacquart
767b3abea1
fix(core): Link existing email users on LDAP sync instead of failing (#28695)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 07:39:02 +00:00
Benjamin Schroth
a1d733bb9a
fix(Embeddings Google Gemini Node): Update wrong default embeddings model (#26977) 2026-04-22 07:31:42 +00:00
Raúl Gómez Morales
dafa89988c
fix(editor): Polish Instance AI traces view and reduce orchestrator chattiness (no-changelog) (#28796) 2026-04-22 07:26:21 +00:00
Dawid Myslak
02953693a6
feat(MiniMax Node): Add standalone MiniMax vendor node (#28748)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
2026-04-22 07:18:02 +00:00
Luca Mattiazzi
714981eea3
feat: Add multiple runs to instanceAI eval (no-changelog) (#28493)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-22 07:11:10 +00:00
Svetoslav Dekov
b453d12a93
fix(core): Preserve credential displayOptions in node description adapter (no-changelog) (#28806)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Albert Alises <albert.alises@gmail.com>
2026-04-22 07:09:45 +00:00
phyllis-noester
852d0825d7
fix(core): Fix publishing dynamic credential chathub flow (#28827) 2026-04-22 06:58:38 +00:00
Albert Alises
c0d56f965b
fix(editor): Hide credential check icon while Instance AI setup card has pending params (no-changelog) (#28823) 2026-04-22 06:58:28 +00:00
Charlie Kolb
86a6d1b1fa
feat(editor): Track favorite toggle events (#28810)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 06:53:57 +00:00
Jaakko Husso
08949a1ac9
feat(core): Make sub-agents aware of the current time on instance AI (no-changelog) (#28809) 2026-04-22 06:53:32 +00:00
Jaakko Husso
0e838deab2
fix(ai-builder): Validate merge node connections matches 'numberInputs' parameter (#28831) 2026-04-22 06:47:15 +00:00
Jaakko Husso
51d35f4709
fix(editor): Fix NDV not loading parameters after refresh on instance AI (no-changelog) (#28836) 2026-04-22 06:46:19 +00:00
Andreas Fitzek
29f0677945
feat(core): Add cluster check interface and decorator (no-changelog) (#28724) 2026-04-22 06:26:38 +00:00
n8n-assistant[bot]
85b7796434
chore: Bundle 2.x (#28844)
Co-authored-by: Matsu <matias.huhta@n8n.io>
Co-authored-by: Dawid Myslak <dawid.myslak@gmail.com>
Co-authored-by: Bernhard Wittmann <bernhard.wittmann@n8n.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Dimitri Lavrenük <20122620+dlavrenuek@users.noreply.github.com>
Co-authored-by: Benjamin Schroth <68321970+schrothbn@users.noreply.github.com>
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
Co-authored-by: Sandra Zollner <sandra.zollner@n8n.io>
Co-authored-by: Milorad FIlipović <milorad@n8n.io>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
2026-04-22 08:51:32 +03:00
Svetoslav Dekov
345ce7f0dc
fix(editor): Restore missing node icons for HTTP-auth credentials (#28814)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:46:03 +00:00
Guillaume Jacquart
a817cbc1c0
fix(core): Guard event log parsing against unbounded memory growth (#28594)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Csaba Tuncsik <csaba@n8n.io>
2026-04-21 15:36:57 +00:00
Iván Ovejero
10dbf32596
feat(core): Scale expression isolate pool to 0 after inactivity (#28472)
Co-authored-by: Danny Martini <danny@n8n.io>
2026-04-21 15:20:01 +00:00
RomanDavydchuk
4869e0a463
fix(editor): HTTP request node showing warning about credentials not set when they are set (#28270) 2026-04-21 15:16:08 +00:00
Irénée
3bd7a2847c
feat(core): Make SSO connection settings configurable via env vars (#28714)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-21 15:14:00 +00:00
Dimitri Lavrenük
9494f41c34
feat: Track computer use connect events (no-changelog) (#28815) 2026-04-21 14:49:48 +00:00
RomanDavydchuk
713c4981b7
fix(editor): Move tooltip for required RMC fields to the right (#28803) 2026-04-21 14:44:45 +00:00
Albert Alises
6db02fe928
fix(MCP Server Trigger Node): Only return error name and message in tool error responses (#28791)
Co-authored-by: Anand Reddy Jonnalagadda <15153801+joan1011@users.noreply.github.com>
2026-04-21 13:43:20 +00:00
Alex Grozav
a88f847708
refactor(editor): Migrate nodeMetadata to workflowDocumentStore (no-changelog) (#28788) 2026-04-21 13:22:52 +00:00
Svetoslav Dekov
7d74c1f04b
fix(editor): Resolve node parameter defaults in Instance AI setup wizard (no-changelog) (#28800)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:04:15 +00:00
Daria
b1ca129496
feat(core): Broadcast workflow updates from MCP tools to open editors (#28709) 2026-04-21 12:26:56 +00:00
Michael Kret
8e49800421
fix: Additional keys in routing nodes (#28758) 2026-04-21 12:24:43 +00:00
Albert Alises
782b2d18b2
fix(ai-builder): Prevent duplicate workflow creation on parallel submits in instance AI (#28793) 2026-04-21 12:21:48 +00:00
Milorad FIlipović
76358a60be
fix(editor): Allow name parameters to be defined by AI (#28763) 2026-04-21 11:52:25 +00:00
Jaakko Husso
86ceb68a05
feat(core): Include workflow names on instance AI confirmations (no-changelog) (#28719)
Co-authored-by: Albert Alises <albert.alises@gmail.com>
2026-04-21 11:24:16 +00:00
Jaakko Husso
2d624a521e
fix(core): Generate title once there's enough user context (#28721) 2026-04-21 10:28:19 +00:00
Matsuuu
ba2c5488c7
Merge tag 'n8n@2.18.0' 2026-04-21 13:32:15 +03:00
Daria
d1c7b31237
fix: Stop persisting client id in session storage to fix duplicate tab problem (no-changelog) (#28769) 2026-04-21 10:02:43 +00:00
Ricardo Espinoza
26ecadcf94
fix(core): Use upsert for MCP OAuth consent to allow re-authorization (#28703) 2026-04-21 09:58:01 +00:00
Svetoslav Dekov
45b5b9e383
fix(editor): Fix instance-ai setup parameter issues not resetting on input (no-changelog) (#28689) 2026-04-21 09:55:29 +00:00
Matsu
cb9882ce9c
ci: Run ci-pr-quality only on n8n team PRs (#28773) 2026-04-21 09:50:16 +00:00
Jaakko Husso
6592ed8047
refactor(core): Move instance AI user settings under actual user settings (no-changelog) (#28706) 2026-04-21 09:47:36 +00:00
Michael Kret
92f1dac835
chore(Microsoft Agent 365 Trigger Node): Change label on toggle to enable Microsoft MCP Servers (#28766) 2026-04-21 09:38:33 +00:00
Vitalii Borovyk
a88ee76553
fix(MongoDB Chat Memory Node): Add connection pool limit (#28042)
Co-authored-by: Eugene <eugene@n8n.io>
2026-04-21 09:21:40 +00:00
Suguru Inoue
b444a95e11
refactor(editor): Migrate workflow object usages (#28534) 2026-04-21 09:17:45 +00:00
Declan Carroll
5e8002ab28
test: Refactor test workflow initialization (#28772) 2026-04-21 09:15:26 +00:00
Guillaume Jacquart
c012b52ac2
feat(core): Bootstrap encryption key set from environment (#28716)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 09:13:11 +00:00
Garrit Franke
fc5424477d
feat(core): Add require-node-api-error ESLint rule for community nodes (no-changelog) (#28454) 2026-04-21 09:12:51 +00:00
Jaakko Husso
cb1244c041
refactor: Use napi-rs/image instead of sharp for screenshots (#28586) 2026-04-21 09:12:14 +00:00
n8n-assistant[bot]
6336f0a447
🚀 Release 2.18.0 (#28768)
Co-authored-by: Matsuuu <16068444+Matsuuu@users.noreply.github.com>
2026-04-21 08:58:38 +00:00
Albert Alises
9ea2ef1840
fix(core): Hide pre-resolved setup requests from Instance AI wizard (#28731) 2026-04-21 08:34:59 +00:00
Milorad FIlipović
5e111975d4
fix(editor): Reset remote values on credentials change (#26282)
Co-authored-by: Elias Meire <elias@meire.dev>
Co-authored-by: Nikhil Kuriakose <nikhilkuria@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-21 08:21:06 +00:00
José Braulio González Valido
87163163e6
fix(core): Add required field validation to MCP OAuth client registration (#28490)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 08:04:54 +00:00
Matsu
95c155859e
ci: Ensure stable npm packages are tagged as latest after release (#28755) 2026-04-21 08:04:21 +00:00
Ricardo Espinoza
575c34eae1
feat(core): Track workflow action source for external API and MCP requests (#28483) 2026-04-21 08:00:04 +00:00
Matsu
0d98d29ae4
ci: Only post QA metrics on n8n-io/n8n monorepo (#28692) 2026-04-21 04:59:06 +00:00
Ali Elkhateeb
9a65549575
feat(API): Add missing credential endpoints (GET by ID and test) (#28519)
Some checks failed
Build: Benchmark Image / build (push) Has been cancelled
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Lint (push) Has been cancelled
CI: Master (Build, Test, Lint) / Performance (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Docker Build Smoke Test / Docker Build (no cache) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Has been cancelled
Docker Build Smoke Test / Notify on nightly smoke test failure (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Release: Create Minor Release PR / Create release PR (push) Has been cancelled
Util: Update Node Popularity / approve-and-automerge (push) Has been cancelled
Release: Create Minor Release PR / Notify Slack (push) Has been cancelled
2026-04-20 20:56:51 +00:00
Dawid Myslak
dd6c28c6d1
fix(Alibaba Cloud Chat Model Node): Add credential-level url field for AI gateway compatibility (#28697) 2026-04-20 19:40:12 +00:00
Joco-95
d14f2546a1
feat: Removes computer use setup logic on Assistant AI opt-in flow and minor UX changes (no-changelog) (#28679) 2026-04-20 18:25:09 +00:00
RomanDavydchuk
d179f667c0
fix(HubSpot Trigger Node): Add missing property selectors (#28595) 2026-04-20 18:05:37 +00:00
Mutasem Aldmour
5b376cb12d
feat(editor): Enable workflow execution from instance AI preview canvas (#28412)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 17:57:03 +00:00
Jaakko Husso
6cfa0ed559
feat(core): Rename instance AI to AI Assistant in the UI texts (no-changelog) (#28732) 2026-04-20 17:49:04 +00:00
Luca Mattiazzi
107c48f65c
fix(core): Ensure single zod instance across workspace packages (#28604) 2026-04-20 17:02:24 +00:00
Svetoslav Dekov
1b13d325f1
fix(editor): Show auth type selector in Instance AI workflow setup (#28707)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:50:21 +00:00
Albert Alises
db83a95522
fix(editor): Gate Instance AI input while setup wizard is open (#28685) 2026-04-20 16:32:14 +00:00
Joco-95
b42c890c5e
chore(core): Switch PostHog environment variables to EU region (#27115) 2026-04-20 16:21:37 +00:00
Albert Alises
3b15e470b5
fix(editor): Advance wizard step on Continue instead of applying setup (#28698) 2026-04-20 16:11:50 +00:00
Marc Littlemore
bef528cb21
fix: Restore OpenAPI schema version (no-changelog) (#28713)
Some checks failed
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
2026-04-20 15:51:44 +00:00
Matsu
0b8fae6c5a
ci: Only run visual storybook on public monorepo (#28699) 2026-04-20 14:25:42 +00:00
José Braulio González Valido
560f300716
test: Add Instance AI workflow evals CI pipeline (no-changelog) (#28366)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 14:15:41 +00:00
Jaakko Husso
73d93d4edf
fix(core): Better titles on instance AI, use common title logic on n8n agents sdk (no-changelog) (#28686) 2026-04-20 13:27:33 +00:00
Matsu
9f71e12e5f
chore: Migrate @n8n/json-schema-to-zod from Jest to Vitest (#28411)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:07:50 +00:00
Stephen Wright
9dd3e59acb
feat(core): Add KeyManagerService for encryption key lifecycle management (#28533) 2026-04-20 12:39:46 +00:00
Albert Alises
657bdf136f
fix(core): Filter stale credentials from setup wizard requests (#28478) 2026-04-20 12:37:51 +00:00
Bernhard Wittmann
2d0b231e31
fix(IMAP Node): Fix out-of-memory crash after ECONNRESET on reconnect (#28290) 2026-04-20 12:27:24 +00:00
Raúl Gómez Morales
c17f5b61fe
fix(editor): Prevent chat window jump when hovering prompt suggestions (no-changelog) (#28683) 2026-04-20 12:19:13 +00:00
Alex Grozav
db1eb91940
refactor(editor): Migrate workflow name consumers to workflowDocumentStore (#28682) 2026-04-20 12:17:08 +00:00
Matsu
a3292b738a
chore: Migrate @n8n/permissions to Vitest (#28408) 2026-04-20 12:14:53 +00:00
Declan Carroll
82ee4a9fce
ci: Strengthen Playwright test resilience (#28687) 2026-04-20 12:06:41 +00:00
Matsu
d608889e88
ci: Allow only bundles to 1.x (#28401) 2026-04-20 11:55:35 +00:00
Matsu
a39618a889
chore: Migrate @n8n/client-oauth2 to vitest (#28404) 2026-04-20 11:54:51 +00:00
oleg
bfee79dc21
fix(core): Fix instance-ai planner and prompts after tool consolidation (no-changelog) (#28684) 2026-04-20 11:29:49 +00:00
Jaakko Husso
3e724303c5
fix(core): Prevent nodes tool crash on flattened required fields (#28670) 2026-04-20 10:48:39 +00:00
RomanDavydchuk
19aadf19f7
fix(ClickUp Node): Unclear error message when using OAuth credentials (#28584)
Co-authored-by: Dawid Myslak <dawid.myslak@gmail.com>
2026-04-20 10:33:23 +00:00
Albert Alises
7b3696f3f7
fix(ai-builder): Scope artifacts panel to resources produced in-thread (#28678) 2026-04-20 10:11:46 +00:00
Albert Alises
35f9bed4de
fix(core): Cascade-cancel dependent planned tasks when a parent task fails (#28656) 2026-04-20 09:50:33 +00:00
Garrit Franke
b1c52dad58
test(core): Add credential isolation tests for same-type credentials (no-changelog) (#28308)
Co-authored-by: Jon <jonathan.bennetts@gmail.com>
2026-04-20 09:04:06 +00:00
Alex Grozav
d037fd4647
refactor(editor): Normalize sharedWithProjects field in workflow document store (no-changelog) (#28078) 2026-04-20 08:50:56 +00:00
Milorad FIlipović
0fc2d90b52
fix(core): Report success from mcp tool if workflow is created in DB (no-changelog) (#28529) 2026-04-20 08:48:32 +00:00
Matsu
b2fdcf16c0
ci: Update minor and patch release schedules (#28511) 2026-04-20 08:47:34 +00:00
RomanDavydchuk
73659cb3e7
fix(Google Gemini Node): Determine the file extention from MIME type for image and video operations (#28616) 2026-04-20 08:16:51 +00:00
Michael Kret
4070930e4c
fix(OpenAI Node): Replace hardcoded models with RLC (#28226) 2026-04-20 08:13:47 +00:00
Rob Hough
e848230947
fix(editor): Improve disabled Google sign-in button styling and tooltip alignment (#28536)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Create Minor Release PR / Create release PR (push) Has been cancelled
Release: Create Minor Release PR / Notify Slack (push) Has been cancelled
2026-04-20 07:31:15 +00:00
James Campbell
7094395cef
fix(Google Cloud Firestore Node): Fix empty array serialization in jsonToDocument (#28213)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Has been cancelled
CI: Master (Build, Test, Lint) / Lint (push) Has been cancelled
CI: Master (Build, Test, Lint) / Performance (push) Has been cancelled
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
2026-04-18 13:48:45 +00:00
Jon
f1dab3e295
feat(Slack Node): Add app_home_opened as a dedicated trigger event (#28626)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Roman Davydchuk <roman.davydchuk@n8n.io>
2026-04-17 19:13:53 +00:00
RomanDavydchuk
ff950e5840
fix: Link to n8n website broken in n8n forms (#28627) 2026-04-17 17:09:14 +00:00
Jon
77d27bc826
fix(core): Guard against undefined config properties in credential overwrites (#28573)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 16:42:34 +00:00
R🂡hul
25e07cab5a
fix(LinkedIn Node): Update LinkedIn API version in request headers (#28564)
Co-authored-by: Jon <jonathan.bennetts@gmail.com>
2026-04-17 14:33:10 +00:00
robrown-hubspot
8c3e692174
fix(HubSpot Node): Rename HubSpot "App Token" auth to "Service Key" (#28479)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Jon <jonathan.bennetts@gmail.com>
2026-04-17 14:20:54 +00:00
Declan Carroll
ef4bfbfe94
ci: Skip non isolated tests (#28615) 2026-04-17 13:03:10 +00:00
Jon
51bc71e897
fix(editor): Restore WASM file paths for cURL import in HTTP Request node (#28610)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Matsuuu <huhta.matias@gmail.com>
2026-04-17 12:41:56 +00:00
Eugene
3b248eedc2
feat(Linear Trigger Node): Add signing secret validation (#28522)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-17 12:33:01 +00:00
Csaba Tuncsik
21317b8945
fix(editor): Re-initialize SSO store after login to populate OIDC redirect URL (#28386) 2026-04-17 12:05:48 +00:00
Jaakko Husso
46aa46d996
fix(editor): Handle plan confirmation correctly at the UI (no-changelog) (#28613) 2026-04-17 12:05:33 +00:00
Jaakko Husso
5c9a732af4
fix(core): Rework Instance ai settings (no-changelog) (#28495) 2026-04-17 11:36:49 +00:00
Mutasem Aldmour
cff2852332
fix(core): Preserve submitted workflow outcome when builder errors after submit (no-changelog) (#28606)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 10:19:42 +00:00
Raúl Gómez Morales
465478a829
feat(editor): Add collapsible sidebar and deferred thread creation to Instance AI (no-changelog) (#28459) 2026-04-17 10:00:37 +00:00
Albert Alises
d17211342e
fix(editor): Improve setup wizard placeholder detection and card completion scoping (#28474) 2026-04-17 08:47:54 +00:00
Stephen Wright
bb96d2e50a
feat(core): Persist deployment_key entries for stability across restarts and key rotation (#28518)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (beta) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (stable) (push) Has been cancelled
Release: Schedule Patch Release PRs / Create patch release PR (${{ matrix.track }}) (v1) (push) Has been cancelled
2026-04-16 19:49:11 +00:00
Mutasem Aldmour
c97c3b4d12
fix(editor): Resolve nodes stuck on loading after execution in instance-ai preview (#28450)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:07:19 +00:00
Garrit Franke
fb2bc1ca5f
feat: Add require-community-node-keyword ESLint rule (no-changelog) (#28395) 2026-04-16 17:26:11 +00:00
Rob Hough
04860d5cd7
fix(editor): Fix styles on disabled Publish button (no-changelog) (#28531) 2026-04-16 16:15:11 +00:00
Stephen Wright
c6534fa0b3
feat: Add Prometheus counters for token exchange (#28453)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-04-16 12:20:38 +00:00
Declan Carroll
bb9bec3ba4
revert: Make Wait node fully durable by removing in-memory execution path (#28538) 2026-04-16 11:42:22 +00:00
Stephen Wright
56f36a6d19
fix: Disable axios built-in proxy for OAuth2 token requests (#28513) 2026-04-16 09:35:15 +00:00
Luca Mattiazzi
e4fc753967
fix(core): Fix dev:ai script in package.json (no-changelog) (#28402)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-04-15 17:11:51 +00:00
Milorad FIlipović
1ecc290107
fix(core): Add strict input validation for workflow() (no-changelog) (#28517) 2026-04-15 14:57:43 +00:00
Jaakko Husso
6bb271d83c
fix(core): Position workflow correctly if opened while on a background tab (no-changelog) (#28421)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Build: Benchmark Image / build (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
2026-04-15 13:26:07 +00:00
Michael Kret
d012346c77
feat: AI Gateway credentials endpoint instance url (#28520) 2026-04-15 12:12:19 +00:00
Tuukka Kantola
6739856aa3
fix(editor): Center sub-node icons and refresh triggers panel icons (#28515)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 10:35:12 +00:00
Suguru Inoue
b3e56437c8
refactor(editor): Migrate usages of workflowObject in canvas operations (#28128) 2026-04-15 10:34:00 +00:00
Milorad FIlipović
e5aaeb53a9
fix(core): Implement data tables name collision detection on pull (#26416)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Nikhil Kuriakose <nikhilkuria@gmail.com>
Co-authored-by: Nikhil Kuriakose <nikhil.kuriakose@n8n.io>
2026-04-15 09:38:08 +00:00
Marcus
8b105cc0cf
feat(core): Support npm registry token authentication to install private community node packages (#28228)
Co-authored-by: Sandra Zollner <sandra.zollner@n8n.io>
2026-04-15 09:28:55 +00:00
Sandra Zollner
34430aedb1
fix(core): Fix public API package update process (#28475) 2026-04-15 09:04:39 +00:00
RomanDavydchuk
30128c9254
fix(Google Drive Node): Continue on error support for download file operation (#28276)
Co-authored-by: Shireen Missi <94372015+ShireenMissi@users.noreply.github.com>
2026-04-15 08:41:15 +00:00
Albert Alises
e20f8e91ce
feat(editor): Add admin toggle for computer use in AI settings (no-changelog) (#28452) 2026-04-15 08:08:39 +00:00
Charlie Kolb
f216fda511
fix(editor): Refine resource dependency badge (#28087) 2026-04-15 07:54:26 +00:00
Suguru Inoue
5368851506
refactor(editor): Migrate Workflow class usages in Vue props and function arguments (#28393) 2026-04-15 07:30:49 +00:00
Matsu
80de266be4
ci: Account for pnpm-workspace changes in bump-versions.mjs (#28503) 2026-04-15 07:02:10 +00:00
Matsu
57af37fc61
chore: Migrate @n8n/stylelint-config to Vitest (#28405) 2026-04-15 06:06:03 +00:00
Matsu
229256ee7c
chore: Migrate @n8n/api-types to Vitest (#28394) 2026-04-15 06:05:11 +00:00
Albert Alises
bb7d137cf7
fix(editor): Display placeholder sentinels as hint text in setup wizard (#28482)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
2026-04-14 16:36:28 +00:00
Milorad FIlipović
62dc073b3d
fix(core): Fix workflow-sdk validation for plain workflow objects (#28416) 2026-04-14 16:29:20 +00:00
Dawid Myslak
3f57f1cc19
refactor(core): Rename AI Gateway credits to wallet with USD amounts (#28436) 2026-04-14 15:29:13 +00:00
Dimitri Lavrenük
819e707a61
feat: Simplify user consent flow for computer-use (no-changelog) (#28266) 2026-04-14 15:13:08 +00:00
Albert Alises
04d57c5fd6
fix(editor): Prevent setup wizard disappearing on requestId-driven remount (#28473) 2026-04-14 14:58:39 +00:00
Dawid Myslak
bd927d9350
feat(MiniMax Chat Model Node): Add MiniMax Chat Model sub-node (#28305) 2026-04-14 14:29:50 +00:00
Csaba Tuncsik
1042350f4e
fix(editor): Reset OIDC form dirty state after saving IdP settings (#28388) 2026-04-14 14:21:49 +00:00
Albert Alises
f54608e6e4
refactor(ai-builder): Consolidate native tools into 10 action families (no-changelog) (#28140) 2026-04-14 14:00:41 +00:00
Csaba Tuncsik
9c97931ca0
fix(editor): Only show role assignment warning modal when value actually changed (#28387) 2026-04-14 13:32:44 +00:00
Stephen Wright
ac41112731
fix(core): Enforce credential access checks in dynamic node parameter requests (#28446) 2026-04-14 13:23:41 +00:00
Bernhard Wittmann
2959b4dc2a
fix(core): Skip npm outdated check for verified-only community packages (#28335) 2026-04-14 13:09:13 +00:00
James Gee
36261fbe7a
feat(core): Configure OIDC settings via env vars (#28185)
Signed-off-by: James Gee <1285296+geemanjs@users.noreply.github.com>
Co-authored-by: Irénée <irenee.ajeneza@n8n.io>
Co-authored-by: Ali Elkhateeb <ali.elkhateeb@n8n.io>
2026-04-14 13:06:22 +00:00
Jaakko Husso
e849041c11
fix(core): Make workflow preview refresh after setup completes (no-changelog) (#28468)
Some checks failed
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Build: Benchmark Image / build (push) Has been cancelled
Util: Sync API Docs / sync-public-api (push) Has been cancelled
2026-04-14 12:41:20 +00:00
Ali Elkhateeb
fa3299d042
fix(core): Handle git fetch failure during source control startup (#28422)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:40:06 +00:00
Sandra Zollner
24015b3449
feat(core): Project based data table creation and transfer (#28323) 2026-04-14 12:38:44 +00:00
Stephen Wright
59edd6ae54
feat: Add deployment_key table, entity, repository, and migration (#28329) 2026-04-14 12:20:22 +00:00
krisn0x
ca871cc10a
feat(core): Support npm dist-tags in community node installation (#28067)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 12:18:28 +00:00
yehorkardash
39189c3985
fix: Update working memory using tools (#28467) 2026-04-14 11:45:57 +00:00
Jaakko Husso
9ef55ca4f9
feat(core): Instance AI preview tags and command bar improvements (no-changelog) (#28383) 2026-04-14 11:38:00 +00:00
Charlie Kolb
90a3f460f1
feat(editor): Support showing full label in tooltip on hover of dropdown menu items (no-changelog) (#28231)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-14 11:33:13 +00:00
Svetoslav Dekov
00b0558c2b
fix(editor): Hide setup parameter issue icons until user interacts with input (#28010)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:14:37 +00:00
Jaakko Husso
094a5b403e
fix(core): Switch to latest artifact when it updates / new one is created (no-changelog) (#28461) 2026-04-14 11:04:02 +00:00
Elias Meire
c9cab112f9
fix(editor): Show relevant node in workflow activation errors (#26691) 2026-04-14 11:03:50 +00:00
Matsu
dcbc3f14bd
chore: Bump axios to 1.15.0 (#28460) 2026-04-14 10:49:05 +00:00
Charlie Kolb
69a62e0906
docs: Add migration timestamp guidance to @n8n/db AGENTS.md (no-changelog) (#28444)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-14 10:40:42 +00:00
RomanDavydchuk
357fb7210a
fix(GraphQL Node): Improve error response handling (#28209) 2026-04-14 10:12:48 +00:00
Danny Martini
98b833a07d
fix(core): Resolve additional keys lazily in VM expression engine (#28430)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
2026-04-14 09:10:20 +00:00
Charlie Kolb
b1a075f760
feat(editor): Add favoriting for projects, folders, workflows and data tables (#26228)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: aikido-pr-checks[bot] <169896070+aikido-pr-checks[bot]@users.noreply.github.com>
2026-04-14 09:09:00 +00:00
Matsu
d6fbe5f847
ci: Run lint:styles as a part of reusable linting workflow (#28449) 2026-04-14 08:44:48 +00:00
Matsu
d496f6f1bd
ci: Replace docker/login-action with retry-wrapped docker login for DockerHub (#28442)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 08:44:12 +00:00
oleg
bd9713bd67
feat(instance-ai): Add Brave Search and Daytona credential types (no-changelog) (#28420)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
2026-04-14 08:15:36 +00:00
Luca Mattiazzi
9078bb2306
feat(ai-builder): Add a binary check to avoid code import in code blocks (no-changelog) (#28382)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-14 08:02:41 +00:00
Mutasem Aldmour
433370dc2f
test: Add isolated local Playwright runner (#28427)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 07:57:24 +00:00
Jaakko Husso
bbc3230dcf
chore: Suppress warning from style lint (#28426) 2026-04-14 07:54:05 +00:00
Albert Alises
3c850f2711
fix(ai-builder): Increase orchestrator max steps from default 5 to 60 (#28429) 2026-04-14 07:51:51 +00:00
Dimitri Lavrenük
b48aeef1f2
fix: Block concurring connection requests in computer use (no-changelog) (#28312) 2026-04-14 07:29:25 +00:00
Andreas Fitzek
e8360a497d
feat(core): Add instance registry service (no-changelog) (#27731) 2026-04-14 06:57:35 +00:00
Bernhard Wittmann
5f8ab01f9b
fix(Schedule Node): Use elapsed-time check to self-heal after missed triggers (#28423)
Some checks are pending
Build: Benchmark Image / build (push) Waiting to run
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.14.1) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (25.x) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Util: Sync API Docs / sync-public-api (push) Waiting to run
2026-04-13 15:44:42 +00:00
James Gee
9a22fe5a25
feat(core): Workflow tracing - add workflow version id (#28424) 2026-04-13 15:25:44 +00:00
Jon
ca71d89d88
fix(core): Handle invalid percent sequences and equals signs in HTTP response headers (#27691)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 15:17:33 +00:00
Garrit Franke
550409923a
feat(core): Add require-node-description-fields ESLint rule for icon and subtitle (#28400) 2026-04-13 14:55:17 +00:00
n8n-release-tag-merge[bot]
60503b60b1 Merge tag 'n8n@2.17.0' 2026-04-13 15:10:41 +00:00
Mutasem Aldmour
df5855d4c6
test(editor): Add comprehensive instance AI e2e tests (#28326)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:40:15 +00:00
Irénée
1108467f44
feat: Enable security policy settings via env vars (#28321) 2026-04-13 14:09:06 +00:00
Albert Alises
39c6217109
fix(ai-builder): Use placeholders for user-provided values instead of hardcoding fake addresses (#28407) 2026-04-13 13:29:31 +00:00
Ali Elkhateeb
6217d08ce9
fix(core): Skip disabled Azure Key Vault secrets and handle partial fetch failures (#28325) 2026-04-13 13:23:38 +00:00
4456 changed files with 355168 additions and 75566 deletions

View File

@ -1,62 +0,0 @@
# Design System Style Review Rules
Use these rules when reviewing CSS/SCSS/Vue style changes, especially in
`packages/frontend/` and `packages/frontend/@n8n/design-system/`.
## 1) Token source priority
Prefer this order when choosing visual values:
1. Semantic tokens from
`packages/frontend/@n8n/design-system/src/css/_tokens.scss`
2. Primitives from
`packages/frontend/@n8n/design-system/src/css/_primitives.scss`
3. Hard-coded values only when no suitable token exists
If no token exists, request a short rationale in the PR.
## 2) Hard-coded visual values
Flag hard-coded visual values and suggest token alternatives. This includes:
- Colors (`#fff`, `rgb()`, `hsl()`, `oklch()`)
- Spacing and sizing (`px`, `rem`, numeric layout constants in styles)
- Radius, border widths/styles, and shadows
- Typography values (font size, weight, line-height)
- Motion values (durations and easing like `cubic-bezier(...)`)
Severity: strong warning (expected migration to tokens/primitives when possible).
## 3) Legacy token usage
In `_tokens.scss`, the compatibility section labeled
"Legacy tokens (kept for compatibility)" is considered legacy usage.
When new or modified code uses these legacy token families, flag it as a
migration opportunity and recommend semantic token usage where available.
Severity: strong warning (discourage new usage, allow compatibility paths).
## 4) Deprecated style and component surfaces
Flag new usage of deprecated/legacy style surfaces in design-system components,
for example:
- `Button.legacy.scss` and legacy button override classes
- Legacy button variants/types (for example `highlight`, `highlight-fill`)
- Legacy component variants that exist for compatibility (for example legacy
tabs variant)
Severity: strong warning (prefer modern semantic variants/components).
## 5) Token substitution changes
If a PR changes one token reference to another (for example
`--text-color` -> `--text-color--subtle`), flag it as a soft warning.
Ask for intent in the PR description/comment:
- Intentional design adjustment, or
- Potential accidental visual regression
Do not treat token substitution as a hard failure by default.

1
.agents/skills Symbolic link
View File

@ -0,0 +1 @@
../.claude/plugins/n8n/skills

View File

@ -0,0 +1,150 @@
---
description: >-
Checks if a community pull request is ready for human review. Verifies CLA
signature, PR title format, description completeness, test coverage, and
cubic-dev-ai issues. Use when given a PR number or branch name to review,
or when the user says /community-pr-review, /pr-review, or asks to check if
a PR is ready for review.
allowed-tools: Bash(gh:*), Bash(git:*), Read, Glob, Grep
---
# Community PR Review
Given a PR number or branch name, determine whether it is ready for human review.
## Steps
### 1. Resolve the PR
If given a branch name, find the PR number first:
```bash
gh pr view <branch> --repo n8n-io/n8n --json number --jq .number
```
### 2. Fetch PR data
```bash
gh pr view <number> --repo n8n-io/n8n \
--json number,title,body,author,headRefName,headRefOid,files,isDraft,state
```
Fetch in parallel:
```bash
# CLA commit status (primary signal) — statuses are newest-first; use the first returned entry
gh api --paginate "repos/n8n-io/n8n/commits/<headRefOid>/statuses" \
--jq '[.[] | select(.context == "license/cla") | {state, description}] | first'
# CLAassistant issue comment (fallback when no commit status) — use the last returned entry
gh api --paginate "repos/n8n-io/n8n/issues/<number>/comments" \
--jq '[.[] | select(.user.login == "CLAassistant") | .body] | last'
# cubic-dev-ai PR review comments (streamed so results concatenate cleanly across pages)
gh api --paginate "repos/n8n-io/n8n/pulls/<number>/comments" \
--jq '.[] | select(.user.login == "cubic-dev-ai[bot]") | {body: .body, path: .path}'
```
### 3. Run the five checks
#### A. CLA signed
Check the `license/cla` commit status first; fall back to the CLAassistant comment if no status exists.
**Commit status** (`context == "license/cla"`):
- `state: "success"` → ✅ signed
- `state: "failure"` or `state: "error"` → ❌ not signed
- `state: "pending"` → ⏳ pending
- Not present → fall back to comment
**CLAassistant issue comment** (fallback):
- Body contains `"All committers have signed the CLA."` → ✅ signed
- Body contains `"not signed"` or a link to sign → ❌ not signed
- No comment → ❌ treat as not signed
#### B. PR title format
For all types except `revert`, the title must match:
```
^(feat|fix|perf|test|docs|refactor|build|ci|chore)(\([a-zA-Z0-9 ]+( Node)?\))?!?: [A-Z].+[^.]$
```
For `revert` titles, the summary is the original commit header (which starts with a lowercase type), so capitalization is not enforced:
```
^revert(\([a-zA-Z0-9 ]+( Node)?\))?!?: .+[^.]$
```
- Type must be one of: `feat fix perf test docs refactor build ci chore revert`
- Scope is optional, in parentheses e.g. `(editor)` or `(Slack Node)`
- Breaking changes: `!` before the colon
- Summary: starts with capital letter (lowercase allowed for `revert:`), no trailing period
- No Linear ticket IDs in the title (e.g. `N8N-1234`)
#### C. PR description completeness
1. **Summary** (`## Summary`) — must have non-empty content below the heading (not just the HTML comment).
2. **Related tickets** (`## Related Linear tickets, Github issues, and Community forum posts`) — acceptable content: a URL (`http`), a GitHub closing keyword (`closes #N`, `fixes #N`, `resolves #N`, etc.), or empty. Only flag if the section heading is missing entirely.
3. **Checklist** (`## Review / Merge checklist`) — all four items must be present. Unchecked checkboxes are expected for community PRs; do **not** flag them as missing.
#### D. Tests
Skip this check if the PR type (from the title) is `docs`, `ci`, `chore`, or `build`.
Otherwise:
1. Identify source files changed: non-test files under `packages/` from the `files` list.
2. If there are source file changes, check out the PR in a temporary worktree:
```bash
git fetch origin pull/<number>/head:pr/<number>
git worktree add /tmp/pr-<number>-review pr/<number>
```
3. Read the changed source files from the worktree to understand whether the changes introduce logic that warrants tests (new functions, bug fixes, behaviour changes, data transformations). Pure config changes, type-only changes, and trivial renames do not require tests.
4. Look for matching test files (`*.test.ts`, `*.spec.ts`, files inside `__tests__/`) among the changed files.
5. **Always clean up the worktree**, even if a previous check failed:
```bash
git worktree remove /tmp/pr-<number>-review --force
git branch -D pr/<number>
```
Report:
- ✅ Tests present, or change does not require tests
- ❌ Source logic changed but no test files found
#### E. cubic-dev-ai issues
Review the PR review comments fetched in step 2. `cubic-dev-ai[bot]` leaves comments for every issue it finds.
- No comments from `cubic-dev-ai[bot]`, or every comment explicitly states no issues were found → ✅
- Any other comment → ❌ report the total count and priority breakdown (e.g. "3 issues: 1× P1, 1× P2, 1× P3")
### 4. Output
Always output valid JSON in this exact shape:
```json
{
"readyForReview": <true if all passing checks allow merge, false otherwise>,
"messageForUser": "<Human-readable summary of what needs to change, written as if posted directly to the PR contributor. 'N/A' if nothing is needed.>",
"checks": {
"CLA": <true if signed, false if not signed or pending>,
"Title": <true if title matches convention, false otherwise>,
"Description": <true if all three template sections are complete, false otherwise>,
"TestsNeeded": <true if the code changes require tests, false if not applicable>,
"TestsIncluded": <true if test files are present in the PR, false otherwise>,
"CubicIssues": <true if cubic-dev-ai raised issues, false if no issues>
}
}
```
`readyForReview` is `true` only when: `CLA`, `Title`, and `Description` are all `true`; `CubicIssues` is `false`; and either `TestsNeeded` is `false` or `TestsIncluded` is `true`.
`messageForUser` should be a short, friendly message directed at the contributor listing exactly what they need to address. If `readyForReview` is `true`, set it to `"N/A"`.
Output nothing other than the JSON block.
## Notes
- Draft PRs — report all findings but note the PR is a draft.
- If the PR is already merged or closed, say so and skip the checks.
- Always remove the worktree even if earlier checks failed.

View File

@ -1,4 +1,5 @@
---
name: n8n:content-design
description: >
Product content designer for UI copy. Use when writing, reviewing, or auditing
user-facing text: button labels, error messages, tooltips, empty states, modal copy,

View File

@ -1,4 +1,5 @@
---
name: n8n:conventions
description: Quick reference for n8n patterns. Full docs /AGENTS.md
---

View File

@ -1,4 +1,5 @@
---
name: n8n:create-community-node-lint-rule
description: >-
Create new ESLint rules for the @n8n/eslint-plugin-community-nodes package.
Use when adding a lint rule, creating a community node lint, or working on

View File

@ -1,4 +1,5 @@
---
name: n8n:create-issue
description: Create Linear tickets or GitHub issues following n8n conventions. Use when the user asks to create a ticket, file a bug, open an issue, or says /create-issue.
argument-hint: "[linear|github] <description of the issue>"
compatibility:

View File

@ -1,4 +1,5 @@
---
name: n8n:create-pr
description: Creates GitHub pull requests with properly formatted titles that pass the check-pr-title CI validation. Use when creating PRs, submitting changes for review, or when the user says /pr or asks to create a pull request.
allowed-tools: Bash(git:*), Bash(gh:*), Read, Grep, Glob
---

View File

@ -1,4 +1,5 @@
---
name: n8n:create-skill
description: >-
Guides users through creating effective Agent Skills. Use when you want to
create, write, or author a new skill, or asks about skill structure, best

View File

@ -0,0 +1,33 @@
---
name: n8n:design-system
description: Guidelines on using Design System styles and components. Use when working on .vue files in packages/frontend. Triggers for tasks that include component architecture, styling, UI changes, or feature work.
---
# Design System
Comprehensive guide for building, styling, and using components in the frontend.
## When to Apply
Reference these guidelines when:
- Working on `.{vue|css|scss}` files in `packages/frontend`
- Adding new components to `packages/frontend/@n8n/design-system`
- Refactoring styles for Vue components
- Implementing new UI components or features
- Reviewing changes to UI
## Rules
- Follow guidelines in `packages/frontend/@n8n/design-system/src/styleguide/*.mdx`
- ALWAYS use CSS variables for styles from `packages/frontend/@n8n/design-system/src/css/_tokens.scss` or `packages/frontend/@n8n/design-system/src/css/_primtivies.scss`. Use hard-coded values only when no suitable tokens.
- ALWAYS prefer using existing components from `packages/frontend/@n8n/design-system/src/components`. Prefer components that aren't marked `@deprecated`.
- Use `light-dark()` when alternating colors for ligh/dark mode
- When working with animations or transitions, ALWAYS prefer using mixins from `packages/frontend/@n8n/design-system/src/css/mixins/motion.scss`
- When reviewing animations, follow the guides in `rules/web-animation-guidelines.md`
- When reviewing UI changes or adding new components, follow `rules/web-interface-guidelines.md`
## Examples
- "Add a modal dialog for confirming workflow deletion" → Use `N8nDialog`
- "Add a dropdown to select workflow status" → Use `N8nDropdown` or `N8nSelect`
- "Add button with + icon to add new tiem" → Wrap `N8nButton` with `iconOnly` prop with `N8nTooltip` and wrap in `N8nTooltip`. Use `N8nIcon` and proper aria-label.
- "Add a destructive action button" → use `N8nButton` with `variant="destructive"`
- "Make background color white/black" → Use `var(--background--surface)` for white on light mode and "black" on dark mode
- "Animate the title in gracefully" -> Use `fade-in-up` mixin from `motion.scss` with `var(--duration--base)`

View File

@ -0,0 +1,93 @@
# Web Motion Guidelines
Design and implement web animations that feel natural and purposeful
## Timing and Duration
## Duration Guidelines
| Element Type | Duration |
| --------------------------------- | --------- |
| Micro-interactions | 100-150ms |
| Standard UI (tooltips, dropdowns) | 150-250ms |
| Modals, drawers | 200-300ms |
**Rules:**
- UI animations should stay under 300ms
- Larger elements animate slower than smaller ones
- Exit animations can be ~20% faster than entrance
- Match duration to distance - longer travel = longer duration
### The Frequency
Determine how often users will see the animation:
- **100+ times/day** → No animation (or drastically reduced)
- **Occasional use** → Standard animation
- **Rare/first-time** → Can be more special
**Example:** Raycast never animates because users open it hundreds of times a day.
## When to Animate
**Do animate:**
- Enter/exit transitions for spatial consistency
- State changes that benefit from visual continuity
- Responses to user actions (feedback)
- Rarely-used interactions where delight adds value
**Don't animate:**
- Keyboard-initiated actions
- Hover effects on frequently-used elements
- Anything users interact with 100+ times daily
- When speed matters more than smoothness
## Performance
Prefer animating `transform` and `opacity`. These skip layout and paint stages, running entirely on the GPU.
**Avoid animating:**
- `padding`, `margin`, `height`, `width` (trigger layout)
- `blur` filters above 20px (expensive, especially Safari)
- CSS variables in deep component trees
### Optimization Techniques
```css
/* Force GPU acceleration */
.animated-element {
will-change: transform;
}
```
## Practical Tips
Quick reference for common scenarios. See [PRACTICAL-TIPS.md](PRACTICAL-TIPS.md) for detailed implementations.
| Scenario | Solution |
| ------------------------------- | ----------------------------------------------- |
| Make buttons feel responsive | Add `transform: scale(0.97)` on `:active` |
| Element appears from nowhere | Start from `scale(0.95)`, not `scale(0)` |
| Shaky/jittery animations | Add `will-change: transform` |
| Hover causes flicker | Animate child element, not parent |
| Popover scales from wrong point | Set `transform-origin` to trigger location |
| Sequential tooltips feel slow | Skip delay/animation after first tooltip |
| Small buttons hard to tap | Use 44px minimum hit area (pseudo-element) |
| Something still feels off | Add subtle blur (under 20px) to mask it |
| Hover triggers on mobile | Use `@media (hover: hover) and (pointer: fine)` |
## Easing Decision Flowchart
Is the element entering or exiting the viewport?
├── Yes → ease-out
└── No
├── Is it moving/morphing on screen?
│ └── Yes → ease-in-out
└── Is it a hover change?
├── Yes → ease
└── Is it constant motion?
├── Yes → linear
└── Default → ease-out

View File

@ -0,0 +1,98 @@
# Web Interface Guidelines
<!-- credit to https://github.com/raunofreiberg/interfaces -->
This document outlines a non-exhaustive list of details that make a good (web) interface. It is a living document, periodically updated based on learnings. Some of these may be subjective, but most apply to all websites.
The [WAI-ARIA](https://www.w3.org/TR/wai-aria-1.1/) spec is deliberately not duplicated in this document. However, some accessibility guidelines may be pointed out. Contributions are welcome. Edit [this file](https://github.com/raunofreiberg/interfaces/blob/main/README.md) and submit a pull request.
## Interactivity
- Clicking the input label should focus the input field
- Inputs should be wrapped with a `<form>` to submit by pressing Enter
- Inputs should have an appropriate `type` like `password`, `email`, etc
- Inputs should disable `spellcheck` and `autocomplete` attributes most of the time
- Inputs should leverage HTML form validation by using the `required` attribute when appropriate
- Input prefix and suffix decorations, such as icons, should be absolutely positioned on top of the text input with padding, not next to it, and trigger focus on the input
- Toggles should immediately take effect, not require confirmation
- Buttons should be disabled after submission to avoid duplicate network requests
- Interactive elements should disable `user-select` for inner content
- Decorative elements (glows, gradients) should disable `pointer-events` to not hijack events
- Interactive elements in a vertical or horizontal list should have no dead areas between each element, instead, increase their `padding`
## Typography
- Fonts should have `-webkit-font-smoothing: antialiased` applied for better legibility
- Fonts should have `text-rendering: optimizeLegibility` applied for better legibility
- Fonts should be subset based on the content, alphabet or relevant language(s)
- Font weight should not change on hover or selected state to prevent layout shift
- Font weights below 400 should not be used
- Medium sized headings generally look best with a font weight between 500-600
- Adjust values fluidly by using CSS [`clamp()`](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp), e.g. `clamp(48px, 5vw, 72px)` for the `font-size` of a heading
- Where available, tabular figures should be applied with `font-variant-numeric: tabular-nums`, particularly in tables or when layout shifts are undesirable, like in timers
- Prevent text resizing unexpectedly in landscape mode on iOS with `-webkit-text-size-adjust: 100%`
## Motion
- Switching themes should not trigger transitions and animations on elements [^1]
- Animation duration should not be more than 200ms for interactions to feel immediate
- Animation values should be proportional to the trigger size:
- Don't animate dialog scale in from 0 → 1, fade opacity and scale from ~0.8
- Don't scale buttons on press from 1 → 0.8, but ~0.96, ~0.9, or so
- Actions that are frequent and low in novelty should avoid extraneous animations: [^2]
- Opening a right click menu
- Deleting or adding items from a list
- Hovering trivial buttons
- Looping animations should pause when not visible on the screen to offload CPU and GPU usage
- Use `scroll-behavior: smooth` for navigating to in-page anchors, with an appropriate offset
## Touch
- Hover states should not be visible on touch press, use `@media (hover: hover)` [^3]
- Font size for inputs should not be smaller than 16px to prevent iOS zooming on focus
- Inputs should not auto focus on touch devices as it will open the keyboard and cover the screen
- Apply `muted` and `playsinline` to `<video />` tags to auto play on iOS
- Disable `touch-action` for custom components that implement pan and zoom gestures to prevent interference from native behavior like zooming and scrolling
- Disable the default iOS tap highlight with `-webkit-tap-highlight-color: rgba(0,0,0,0)`, but always replace it with an appropriate alternative
## Optimizations
- Large `blur()` values for `filter` and `backdrop-filter` may be slow
- Scaling and blurring filled rectangles will cause banding, use radial gradients instead
- Sparingly enable GPU rendering with `transform: translateZ(0)` for unperformant animations
- Toggle `will-change` on unperformant scroll animations for the duration of the animation [^4]
- Auto-playing too many videos on iOS will choke the device, pause or even unmount off-screen videos
- Bypass React's render lifecycle with refs for real-time values that can commit to the DOM directly [^5]
- [Detect and adapt](https://github.com/GoogleChromeLabs/react-adaptive-hooks) to the hardware and network capabilities of the user's device
## Accessibility
- Disabled buttons should not have tooltips, they are not accessible [^6]
- Focusable elements in a sequential list should be navigable with <kbd></kbd> <kbd></kbd>
- Focusable elements in a sequential list should be deletable with <kbd></kbd> <kbd>Backspace</kbd>
- To open immediately on press, dropdown menus should trigger on `mousedown`, not `click`
- Use a svg favicon with a style tag that adheres to the system theme based on `prefers-color-scheme`
- Icon only interactive elements should define an explicit `aria-label`
- Tooltips triggered by hover should not contain interactive content
- Images should always be rendered with `<img>` for screen readers and ease of copying from the right click menu
- Illustrations built with HTML should have an explicit `aria-label` instead of announcing the raw DOM tree to people using screen readers
- Gradient text should unset the gradient on `::selection` state
- When using nested menus, use a "prediction cone" to prevent the pointer from accidentally closing the menu when moving across other elements.
## Design
- Optimistically update data locally and roll back on server error with feedback
- Authentication redirects should happen on the server before the client loads to avoid janky URL changes
- Style the document selection state with `::selection`
- Display feedback relative to its trigger:
- Show a temporary inline checkmark on a successful copy, not a notification
- Highlight the relevant input(s) on form error(s)
- Empty states should prompt to create a new item, with optional templates
[^1]: Switching between dark mode or light mode will trigger transitions on elements that are meant for explicit interactions like hover. We can [disable transitions temporarily](https://paco.me/writing/disable-theme-transitions) to prevent this. For Next.js, use [next-themes](https://github.com/pacocoursey/next-themes) which prevents transitions out of the box.
[^2]: This is a matter of taste but some interactions just feel better with no motion. For example, the native macOS right click menu only animates out, not in, due to the frequent usage of it.
[^3]: Most touch devices on press will temporarily flash the hover state, unless explicitly only defined for pointer devices with [`@media (hover: hover)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover).
[^4]: Use [`will-change`](https://developer.mozilla.org/en-US/docs/Web/CSS/will-change) as a last resort to improve performance. Pre-emptively throwing it on elements for better performance may have the opposite effect.
[^5]: This might be controversial but sometimes it can be beneficial to manipulate the DOM directly. For example, instead of relying on React re-rendering on every wheel event, we can track the delta in a ref and update relevant elements directly in the callback.
[^6]: Disabled buttons do not appear in tab order in the DOM so the tooltip will never be announced for keyboard users and they won't know why the button is disabled.
[^7]: As of 2023, Safari will not take the border radius of an element into account when defining custom outline styles. [Safari 16.4](https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes) has added support for `outline` following the curve of border radius. However, keep in mind that not everyone updates their OS immediately.

View File

@ -1,6 +1,6 @@
---
name: n8n:linear-issue
description: Fetch and analyze Linear issue with all related context. Use when starting work on a Linear ticket, analyzing issues, or gathering context about a Linear issue.
disable-model-invocation: true
argument-hint: "[issue-id]"
compatibility:
requires:

View File

@ -1,4 +1,5 @@
---
name: n8n:loom-transcript
description: Fetch and display the full transcript from a Loom video URL. Use when the user wants to get or read a Loom transcript.
argument-hint: [loom-url]
---
@ -101,4 +102,4 @@ Format and present the full transcript to the user:
- No authentication or cookies are required — Loom's transcript API is publicly accessible.
- Only English transcripts are available through this API.
- Transcripts are auto-generated and may contain minor errors.
- Transcripts are auto-generated and may contain minor errors.

View File

@ -1,4 +1,5 @@
---
name: n8n:node-add-oauth
description: Add OAuth2 credential support to an existing n8n node — creates the credential file, updates the node, adds tests, and keeps the CLI constant in sync. Use when the user says /node-add-oauth.
argument-hint: "[node-name] [optional: custom-scopes flag or scope list]"
---

View File

@ -0,0 +1,139 @@
---
name: n8n:protect-endpoints
description: Applies n8n's RBAC scope decorators to REST endpoints. Use when creating a new @RestController, adding any @Get/@Post/@Put/@Patch/@Delete route to an existing controller, or reviewing endpoint authorization. Every authenticated endpoint must be gated by @ProjectScope or @GlobalScope.
---
# Protect REST endpoints with RBAC
**Rule:** every authenticated route on a `@RestController` MUST carry an access-scope decorator. If you add a route without one, the IDOR/permission bypass is on you.
## Decision
```
URL has :projectId → @ProjectScope('<resource>:<op>')
URL has no project → @GlobalScope('<resource>:<op>')
skipAuth: true → no decorator + comment explaining alternate auth
```
`@ProjectScope` succeeds if the user has the scope **globally OR in the project named in the URL**. `@GlobalScope` ignores project relations entirely.
Both decorators come from `@n8n/decorators`. The middleware lives in `packages/cli/src/controller.registry.ts` (`createScopedMiddleware`) and resolves access via `userHasScopes` in `packages/cli/src/permissions.ee/check-access.ts`.
## Apply the decorator
```ts
import { Get, Post, ProjectScope, RestController } from '@n8n/decorators';
@RestController('/projects/:projectId/widgets')
export class WidgetsController {
@Post('/')
@ProjectScope('widget:create') // create
async create(...) { ... }
@Get('/:widgetId')
@ProjectScope('widget:read') // read one
async get(...) { ... }
@Get('/')
@ProjectScope('widget:list') // list
async list(...) { ... }
@Patch('/:widgetId')
@ProjectScope('widget:update') // update
async update(...) { ... }
@Delete('/:widgetId')
@ProjectScope('widget:delete') // delete
async delete(...) { ... }
}
```
Conventions:
- One decorator per route, placed directly under the HTTP-method decorator.
- Use the most specific scope that fits. Reuse `*:update` for state-changing actions like `publish`/`unpublish`/`build` unless the resource needs to gate them separately (see `workflow:publish` for the precedent).
- Routes without `:projectId` and not global-only operations are usually a design smell — flag it.
## When the scope doesn't exist yet
Add the resource and ops in `packages/@n8n/permissions/`:
1. **`src/constants.ee.ts`** — add to `RESOURCES` (alphabetical):
```ts
widget: [...DEFAULT_OPERATIONS, 'execute'] as const,
```
The `Scope` union (`<resource>:<op>` template-literal type) auto-derives.
2. **`src/scope-information.ts`** — add a display name + description per scope.
3. **`src/roles/scopes/project-scopes.ee.ts`** — add to project roles. Match the `workflow` precedent unless product says otherwise:
- `REGULAR_PROJECT_ADMIN_SCOPES`, `PERSONAL_PROJECT_OWNER_SCOPES`, `PROJECT_EDITOR_SCOPES` → all CRUDL+execute scopes.
- `PROJECT_VIEWER_SCOPES` → read/list/execute only.
- `PROJECT_CHAT_USER_SCOPES` → execute only (if applicable).
4. **`src/roles/scopes/global-scopes.ee.ts`** — add to `GLOBAL_OWNER_SCOPES` (admin inherits via `concat()`). Do **not** add to member/chat-user globals — they get scopes via project relations.
5. **Personal-space publishing**: if you add a `<resource>:publish` scope, also append it to `PERSONAL_SPACE_PUBLISHING_SETTING.scopes` in `constants.ee.ts` so personal-owner gating matches `workflow:publish`.
6. **Frontend wiring** — three files in the editor; skipping any of them means the new scopes will not appear in the project-role configuration UI:
- `packages/frontend/editor-ui/src/app/stores/rbac.store.ts` — add `<resource>: {}` to `scopesByResourceId` (typecheck will fail otherwise).
- `packages/frontend/editor-ui/src/features/project-roles/projectRoleScopes.ts` — add the resource to `UI_OPERATIONS` (operations to render in the permissions matrix, in display order) **and** to `SCOPE_TYPES` (the order the resource group appears on the page).
- `packages/frontend/@n8n/i18n/src/locales/en.json` — add `projectRoles.<resource>:<op>` (column label) and `projectRoles.<resource>:<op>.tooltip` (hover description) for every op, plus `projectRoles.type.<resource>` (the group header).
7. **Snapshot** — update `packages/@n8n/permissions/src/__tests__/__snapshots__/scope-information.test.ts.snap` to include the new `<resource>:*` entries.
No DB migration needed — `AuthRolesService.init()` syncs scopes/roles on every startup. Custom team roles created in the UI are **not** auto-updated; mention this in the PR description.
## Public / unauthenticated routes
`{ skipAuth: true }` skips the auth middleware → `req.user` is undefined → adding `@ProjectScope` would 401 every call. Public routes (third-party webhooks, signed callbacks) must:
1. **Omit the scope decorator.**
2. Authenticate via signature/HMAC verification inside the handler (or another route-specific mechanism).
3. Carry a comment explaining why no scope is applied, so the next reviewer doesn't try to "fix" it.
Example:
```ts
// Third-party webhook callback: do not add @ProjectScope. Auth happens
// via per-platform signature verification inside webhookHandler, and
// :projectId is unused in the (agentId, platform) lookup.
@Post('/:agentId/webhooks/:platform', { skipAuth: true, allowBots: true })
async handleWebhook(...) { ... }
```
## Verify with a route-metadata test
Add a regression test that fails when a future route is added without a scope. Iterate every route on the controller via `ControllerRegistryMetadata` and assert the gate.
```ts
import { ControllerRegistryMetadata } from '@n8n/decorators';
import { Container } from '@n8n/di';
import { WidgetsController } from '../widgets.controller';
const UNAUTHENTICATED_HANDLERS = new Set<string>(); // add public handler names here
const metadata = Container.get(ControllerRegistryMetadata).getControllerMetadata(
WidgetsController as never,
);
const routeCases = Array.from(metadata.routes.entries()).map(([handlerName, route]) => ({
handlerName, route,
}));
describe('WidgetsController route access scopes', () => {
it.each(routeCases)(
'$handlerName is gated by a project-scoped widget:* check',
({ handlerName, route }) => {
if (UNAUTHENTICATED_HANDLERS.has(handlerName)) {
expect(route.accessScope).toBeUndefined();
expect(route.skipAuth).toBe(true);
return;
}
expect(route.accessScope).toBeDefined();
expect(route.accessScope?.globalOnly).toBe(false);
expect(route.accessScope?.scope.startsWith('widget:')).toBe(true);
},
);
});
```
## Defense in depth (still required)
Decorator alone is not enough when handlers leak data via downstream calls. Service/repository methods should still **filter by `projectId`** (or user-scoped helpers like `findByUser`). The decorator gates *who can call this URL*; the service gates *what they can read*. Both, always.
## Reference patterns
- Project-scoped CRUD: `packages/cli/src/workflows/workflows.controller.ts`, `packages/cli/src/credentials/credentials.controller.ts`, `packages/cli/src/modules/data-table/data-table.controller.ts`.
- Mixed global + project: `packages/cli/src/controllers/project.controller.ts`.

View File

@ -1,4 +1,5 @@
---
name: n8n:reproduce-bug
description: Reproduce a bug from a Linear ticket with a failing test. Expects the full ticket context (title, description, comments) to be provided as input.
---

View File

@ -1,4 +1,5 @@
---
name: n8n:setup-mcps
description: >-
Configure MCP servers for n8n development. Use when the user says /setup-mcps
or asks to set up MCP servers for n8n.

View File

@ -1,4 +1,5 @@
---
name: n8n:spec-driven-development
description: Keeps implementation and specs in sync. Use when working on a feature that has a spec in .claude/specs/, when the user says /spec, or when starting implementation of a documented feature. Also use when the user asks to verify implementation against a spec or update a spec after changes.
---

1
.claude/skills Symbolic link
View File

@ -0,0 +1 @@
plugins/n8n/skills

545
.code-health-baseline.json Normal file
View File

@ -0,0 +1,545 @@
{
"version": 1,
"generated": "2026-05-12T09:37:31.489Z",
"totalViolations": 82,
"violations": {
"packages/@n8n/ai-workflow-builder.ee/package.json": [
{
"rule": "catalog-violations",
"line": 73,
"message": "langsmith@^0.4.6 should use \"catalog:\" (exists in pnpm-workspace.yaml)",
"hash": "6ee5e003d795"
},
{
"rule": "catalog-violations",
"line": 61,
"message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "d2120f012c93"
},
{
"rule": "catalog-violations",
"line": 70,
"message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "94f80b083b76"
},
{
"rule": "catalog-violations",
"line": 71,
"message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9c770d66baf2"
},
{
"rule": "catalog-violations",
"line": 77,
"message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "85c311d87491"
},
{
"rule": "catalog-violations",
"line": 83,
"message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "407c8d1b3428"
}
],
"packages/@n8n/json-schema-to-zod/package.json": [
{
"rule": "catalog-violations",
"line": 63,
"message": "zod@^3.25.76 should use \"catalog:\" (exists in pnpm-workspace.yaml)",
"hash": "0e18482e8781"
}
],
"packages/@n8n/nodes-langchain/package.json": [
{
"rule": "catalog-violations",
"line": 292,
"message": "openai@^6.34.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)",
"hash": "3c1f53f0afe3"
},
{
"rule": "catalog-violations",
"line": 299,
"message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "88d67e2ef747"
},
{
"rule": "catalog-violations",
"line": 259,
"message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "69d6fa7e46f9"
},
{
"rule": "catalog-violations",
"line": 274,
"message": "cheerio appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "8cd029bb871e"
},
{
"rule": "catalog-violations",
"line": 284,
"message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "26f20ebea4b1"
},
{
"rule": "catalog-violations",
"line": 289,
"message": "mongodb appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "46cb48884e22"
},
{
"rule": "catalog-violations",
"line": 293,
"message": "pdf-parse appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "0c7d44a9c2e4"
}
],
"packages/@n8n/tournament/package.json": [
{
"rule": "catalog-violations",
"line": 44,
"message": "@types/node@^18.13.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)",
"hash": "6368b5d3b924"
},
{
"rule": "catalog-violations",
"line": 52,
"message": "typescript@^5.0.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)",
"hash": "f668021a144e"
},
{
"rule": "catalog-violations",
"line": 55,
"message": "ast-types appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "27edcbb2b4f8"
},
{
"rule": "catalog-violations",
"line": 56,
"message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "75058f9a4d30"
},
{
"rule": "catalog-violations",
"line": 57,
"message": "recast appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "5f2b50fef19d"
}
],
"packages/frontend/@n8n/chat/package.json": [
{
"rule": "catalog-violations",
"line": 56,
"message": "unplugin-icons@^0.19.0 should use \"catalog:frontend\" (exists in pnpm-workspace.yaml [frontend])",
"hash": "a0d24d761026"
}
],
"packages/frontend/@n8n/design-system/package.json": [
{
"rule": "catalog-violations",
"line": 73,
"message": "@vueuse/core@* should use \"catalog:frontend\" (exists in pnpm-workspace.yaml [frontend])",
"hash": "237e9d17c4ba"
}
],
"packages/cli/package.json": [
{
"rule": "catalog-violations",
"line": 98,
"message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "1e3686e1923b"
},
{
"rule": "catalog-violations",
"line": 139,
"message": "@opentelemetry/sdk-trace-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "1cf7f6bcf5d1"
},
{
"rule": "catalog-violations",
"line": 140,
"message": "@opentelemetry/sdk-trace-node appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "a3dad0b8dc21"
},
{
"rule": "catalog-violations",
"line": 150,
"message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "949e802528f7"
},
{
"rule": "catalog-violations",
"line": 202,
"message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "3cab98902302"
},
{
"rule": "catalog-violations",
"line": 209,
"message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "5b7e9b03fb10"
},
{
"rule": "catalog-violations",
"line": 217,
"message": "undici appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "91c29775e961"
},
{
"rule": "catalog-violations",
"line": 220,
"message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "cd07242e8163"
},
{
"rule": "catalog-violations",
"line": 75,
"message": "@types/psl appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "6e62e0076b0a"
}
],
"packages/@n8n/agents/package.json": [
{
"rule": "catalog-violations",
"line": 28,
"message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "b58f03d0d5c1"
},
{
"rule": "catalog-violations",
"line": 50,
"message": "@opentelemetry/sdk-trace-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "c5c495ac3508"
},
{
"rule": "catalog-violations",
"line": 51,
"message": "@opentelemetry/sdk-trace-node appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "a77ced903cdf"
}
],
"packages/@n8n/instance-ai/package.json": [
{
"rule": "catalog-violations",
"line": 80,
"message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "5b2153508e47"
},
{
"rule": "catalog-violations",
"line": 86,
"message": "@types/psl appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "56dabb51b433"
},
{
"rule": "catalog-violations",
"line": 56,
"message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "8fa6b9a8fc91"
},
{
"rule": "catalog-violations",
"line": 64,
"message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "8f082fc2e8b6"
},
{
"rule": "catalog-violations",
"line": 71,
"message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9a9d97065952"
},
{
"rule": "catalog-violations",
"line": 87,
"message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "12e346c47b39"
},
{
"rule": "catalog-violations",
"line": 50,
"message": "@joplin/turndown-plugin-gfm appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "a3cf1504b5c2"
},
{
"rule": "catalog-violations",
"line": 68,
"message": "pdf-parse appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "283fa9114c03"
}
],
"packages/node-dev/package.json": [
{
"rule": "catalog-violations",
"line": 47,
"message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "6988b9f58c92"
},
{
"rule": "catalog-violations",
"line": 46,
"message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "da9b64834300"
},
{
"rule": "catalog-violations",
"line": 53,
"message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "632a744e397e"
}
],
"packages/nodes-base/package.json": [
{
"rule": "catalog-violations",
"line": 911,
"message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "2d1fab7a5b05"
},
{
"rule": "catalog-violations",
"line": 961,
"message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "2daf37aa14e4"
},
{
"rule": "catalog-violations",
"line": 966,
"message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "3f93c404ae9c"
},
{
"rule": "catalog-violations",
"line": 900,
"message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "ca4ac788adc6"
},
{
"rule": "catalog-violations",
"line": 912,
"message": "cheerio appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "1a1b5bbc50c9"
},
{
"rule": "catalog-violations",
"line": 915,
"message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "781db4a1e068"
},
{
"rule": "catalog-violations",
"line": 917,
"message": "eventsource appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9795e6c6d9e9"
},
{
"rule": "catalog-violations",
"line": 930,
"message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "02341f2b5e3e"
},
{
"rule": "catalog-violations",
"line": 941,
"message": "mongodb appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "f688907d087a"
},
{
"rule": "catalog-violations",
"line": 892,
"message": "eslint-plugin-n8n-nodes-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "ac254baa61f9"
}
],
"packages/@n8n/node-cli/package.json": [
{
"rule": "catalog-violations",
"line": 52,
"message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "da74ed210d07"
},
{
"rule": "catalog-violations",
"line": 59,
"message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "188baf266f61"
},
{
"rule": "catalog-violations",
"line": 51,
"message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9711a9b00bf9"
},
{
"rule": "catalog-violations",
"line": 55,
"message": "eslint-plugin-n8n-nodes-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "6a9e12780943"
}
],
"packages/frontend/editor-ui/package.json": [
{
"rule": "catalog-violations",
"line": 69,
"message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "bd9a2eeb072b"
},
{
"rule": "catalog-violations",
"line": 90,
"message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9e9c7ec09a0b"
},
{
"rule": "catalog-violations",
"line": 92,
"message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "d8c606e42c92"
},
{
"rule": "catalog-violations",
"line": 77,
"message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "62156c2613b2"
}
],
"packages/@n8n/scan-community-package/package.json": [
{
"rule": "catalog-violations",
"line": 20,
"message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "ac0e4301d694"
}
],
"packages/@n8n/ai-utilities/package.json": [
{
"rule": "catalog-violations",
"line": 69,
"message": "undici appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "c14cd05614e8"
},
{
"rule": "catalog-violations",
"line": 65,
"message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "884a45bdbcf2"
},
{
"rule": "catalog-violations",
"line": 72,
"message": "n8n-workflow appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "ea4fbfff30ba"
}
],
"packages/@n8n/mcp-browser/package.json": [
{
"rule": "catalog-violations",
"line": 36,
"message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "9650c1b55f3c"
},
{
"rule": "catalog-violations",
"line": 28,
"message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "0c97891a24f4"
},
{
"rule": "catalog-violations",
"line": 30,
"message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "8466b03b1044"
},
{
"rule": "catalog-violations",
"line": 35,
"message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "f23a9d3d7aa2"
},
{
"rule": "catalog-violations",
"line": 42,
"message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "3f9e46e56803"
},
{
"rule": "catalog-violations",
"line": 26,
"message": "@joplin/turndown-plugin-gfm appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "743e3a7dbb32"
}
],
"packages/@n8n/task-runner/package.json": [
{
"rule": "catalog-violations",
"line": 50,
"message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "51cb5069f382"
}
],
"packages/@n8n/benchmark/package.json": [
{
"rule": "catalog-violations",
"line": 36,
"message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "67f9d81d9528"
}
],
"packages/@n8n/cli/package.json": [
{
"rule": "catalog-violations",
"line": 74,
"message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "733c3960022e"
}
],
"packages/workflow/package.json": [
{
"rule": "catalog-violations",
"line": 58,
"message": "ast-types appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "1c7d7cf0b0fe"
},
{
"rule": "catalog-violations",
"line": 60,
"message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "627a716b5d23"
},
{
"rule": "catalog-violations",
"line": 68,
"message": "recast appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "b660317b5f6f"
}
],
"packages/@n8n/computer-use/package.json": [
{
"rule": "catalog-violations",
"line": 47,
"message": "eventsource appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "f50c1eee2ed6"
}
],
"packages/@n8n/eslint-plugin-community-nodes/package.json": [
{
"rule": "catalog-violations",
"line": 47,
"message": "n8n-workflow appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "c5830b76ff8e"
}
],
"packages/@n8n/stylelint-config/package.json": [
{
"rule": "catalog-violations",
"line": 29,
"message": "stylelint appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "955f3fe044c7"
},
{
"rule": "catalog-violations",
"line": 45,
"message": "stylelint appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog",
"hash": "955f3fe044c7"
}
]
}
}

View File

@ -38,3 +38,4 @@
!packages/@n8n/benchmark/**
!packages/@n8n/typescript-config
!packages/@n8n/typescript-config/**

9
.github/CODEOWNERS vendored
View File

@ -1,6 +1,5 @@
packages/@n8n/db/src/migrations/ @n8n-io/migrations-review
.github/workflows @n8n-io/ci-admins
.github/scripts @n8n-io/ci-admins
.github/actions @n8n-io/ci-admins
.github/poutine-rules @n8n-io/ci-admins
.github/workflows @n8n-io/qa-dx
.github/scripts @n8n-io/qa-dx
.github/actions @n8n-io/qa-dx
.github/poutine-rules @n8n-io/qa-dx

232
.github/OWNERS vendored Normal file
View File

@ -0,0 +1,232 @@
# n8n CODEOWNERS
#
# Last-match-wins: specific rules MUST come AFTER general rules.
# Default catch-all (ensures every file gets at least one reviewer)
* @n8n-io/catalysts
# Catalysts
packages/core/ @n8n-io/catalysts
packages/workflow/ @n8n-io/catalysts
packages/@n8n/config/ @n8n-io/catalysts
packages/@n8n/backend-common/ @n8n-io/catalysts
packages/@n8n/backend-test-utils/ @n8n-io/catalysts
packages/@n8n/di/ @n8n-io/catalysts
packages/@n8n/errors/ @n8n-io/catalysts
packages/@n8n/constants/ @n8n-io/catalysts
packages/@n8n/utils/ @n8n-io/catalysts
packages/@n8n/api-types/ @n8n-io/catalysts
packages/@n8n/workflow-sdk/ @n8n-io/instance-ai
packages/@n8n/task-runner/ @n8n-io/catalysts
packages/@n8n/task-runner-python/ @n8n-io/catalysts
packages/@n8n/expression-runtime/ @n8n-io/catalysts
packages/@n8n/db/ @n8n-io/catalysts
packages/@n8n/json-schema-to-zod/ @n8n-io/catalysts
packages/@n8n/crdt/ @n8n-io/catalysts
packages/@n8n/extension-sdk/ @n8n-io/catalysts
packages/@n8n/eslint-config/ @n8n-io/qa-dx
packages/@n8n/typescript-config/ @n8n-io/qa-dx
packages/@n8n/db/src/migrations/ @n8n-io/migrations-review
# Top-level paths
scripts/ @n8n-io/qa-dx
patches/ @n8n-io/qa-dx
assets/ @n8n-io/adore
security/ @n8n-io/qa-dx
# @n8n/cli
packages/@n8n/cli/ @n8n-io/adore
packages/@n8n/cli/src/commands/credential/ @n8n-io/iam
packages/@n8n/cli/src/commands/user/ @n8n-io/iam
packages/@n8n/cli/src/commands/data-table/ @n8n-io/adore
packages/@n8n/cli/src/commands/tag/ @n8n-io/adore
packages/@n8n/cli/src/commands/project/ @n8n-io/ligo
packages/@n8n/cli/src/commands/source-control/ @n8n-io/ligo
packages/@n8n/cli/src/commands/variable/ @n8n-io/ligo
packages/@n8n/cli/src/commands/skill/ @n8n-io/ai
# packages/cli
packages/cli/ @n8n-io/catalysts
packages/cli/src/scaling/ @n8n-io/catalysts
packages/cli/src/concurrency/ @n8n-io/catalysts
packages/cli/src/execution-lifecycle/ @n8n-io/catalysts
packages/cli/src/executions/ @n8n-io/catalysts
packages/cli/src/task-runners/ @n8n-io/catalysts
packages/cli/src/webhooks/ @n8n-io/catalysts
packages/cli/src/push/ @n8n-io/catalysts
packages/cli/src/commands/ @n8n-io/catalysts
packages/cli/src/config/ @n8n-io/catalysts
packages/cli/src/eventbus/ @n8n-io/catalysts
packages/cli/src/events/ @n8n-io/catalysts
packages/cli/src/security-audit/ @n8n-io/catalysts
packages/cli/src/modules/workflow-index/ @n8n-io/catalysts
packages/cli/src/modules/breaking-changes/ @n8n-io/catalysts
packages/cli/src/modules/otel/ @n8n-io/ligo
packages/cli/src/auth/ @n8n-io/iam
packages/cli/src/credentials/ @n8n-io/iam
packages/cli/src/mfa/ @n8n-io/iam
packages/cli/src/oauth/ @n8n-io/iam
packages/cli/src/permissions.ee/ @n8n-io/iam
packages/cli/src/sso.ee/ @n8n-io/iam
packages/cli/src/user-management/ @n8n-io/iam
packages/cli/src/license/ @n8n-io/iam
packages/cli/src/modules/ldap.ee/ @n8n-io/iam
packages/cli/src/modules/log-streaming.ee/ @n8n-io/iam
packages/cli/src/modules/sso-oidc/ @n8n-io/iam
packages/cli/src/modules/sso-saml/ @n8n-io/iam
packages/cli/src/modules/provisioning.ee/ @n8n-io/iam
packages/cli/src/modules/dynamic-credentials.ee/ @n8n-io/iam
packages/cli/src/modules/redaction/ @n8n-io/iam
packages/cli/src/modules/instance-registry/ @n8n-io/iam
packages/cli/src/modules/token-exchange/ @n8n-io/iam
packages/cli/src/environments.ee/ @n8n-io/ligo
packages/cli/src/public-api/ @n8n-io/ligo
packages/cli/src/modules/source-control.ee/ @n8n-io/ligo
packages/cli/src/modules/external-secrets.ee/ @n8n-io/ligo
packages/cli/src/modules/insights/ @n8n-io/ligo
packages/cli/src/collaboration/ @n8n-io/catalysts
packages/cli/src/binary-data/ @n8n-io/catalysts
packages/cli/src/posthog/ @n8n-io/adore
packages/cli/src/modules/data-table/ @n8n-io/adore
packages/cli/src/evaluation.ee/ @n8n-io/ai
packages/cli/src/chat/ @n8n-io/ai
packages/cli/src/tool-generation/ @n8n-io/ai
packages/cli/src/modules/workflow-builder/ @n8n-io/ai
packages/cli/src/modules/mcp/ @n8n-io/ai
packages/cli/src/modules/quick-connect/ @n8n-io/ai
packages/cli/src/modules/chat-hub/ @n8n-io/ai
packages/cli/src/modules/instance-ai/ @n8n-io/instance-ai
packages/cli/src/modules/community-packages/ @n8n-io/nodes
# CLI controllers
packages/cli/src/controllers/auth.controller.ts @n8n-io/iam
packages/cli/src/controllers/invitation.controller.ts @n8n-io/iam
packages/cli/src/controllers/me.controller.ts @n8n-io/iam
packages/cli/src/controllers/mfa.controller.ts @n8n-io/iam
packages/cli/src/controllers/owner.controller.ts @n8n-io/iam
packages/cli/src/controllers/password-reset.controller.ts @n8n-io/iam
packages/cli/src/controllers/role.controller.ts @n8n-io/iam
packages/cli/src/controllers/users.controller.ts @n8n-io/iam
packages/cli/src/controllers/user-settings.controller.ts @n8n-io/iam
packages/cli/src/controllers/api-keys.controller.ts @n8n-io/iam
packages/cli/src/controllers/security-settings.controller.ts @n8n-io/iam
packages/cli/src/controllers/oauth/ @n8n-io/iam
packages/cli/src/controllers/ai.controller.ts @n8n-io/ai
packages/cli/src/controllers/annotation-tags.controller.ee.ts @n8n-io/ai
packages/cli/src/controllers/cta.controller.ts @n8n-io/adore
packages/cli/src/controllers/folder.controller.ts @n8n-io/adore
packages/cli/src/controllers/tags.controller.ts @n8n-io/adore
packages/cli/src/controllers/binary-data.controller.ts @n8n-io/adore
packages/cli/src/controllers/dynamic-templates.controller.ts @n8n-io/adore
packages/cli/src/controllers/posthog.controller.ts @n8n-io/adore
packages/cli/src/controllers/translation.controller.ts @n8n-io/adore
packages/cli/src/controllers/project.controller.ts @n8n-io/ligo
packages/cli/src/controllers/workflow-statistics.controller.ts @n8n-io/ligo
packages/cli/src/controllers/node-types.controller.ts @n8n-io/nodes
packages/cli/src/controllers/dynamic-node-parameters.controller.ts @n8n-io/nodes
packages/cli/src/controllers/e2e.controller.ts @n8n-io/qa-dx
# CLI services
packages/cli/src/services/jwt.service.ts @n8n-io/iam
packages/cli/src/services/user.service.ts @n8n-io/iam
packages/cli/src/services/role.service.ts @n8n-io/iam
packages/cli/src/services/role-cache.service.ts @n8n-io/iam
packages/cli/src/services/password.utility.ts @n8n-io/iam
packages/cli/src/services/public-api-key.service.ts @n8n-io/iam
packages/cli/src/services/security-settings.service.ts @n8n-io/iam
packages/cli/src/services/ssrf/ @n8n-io/catalysts
packages/cli/src/services/static-auth-service.ts @n8n-io/iam
packages/cli/src/services/access.service.ts @n8n-io/iam
packages/cli/src/services/ai.service.ts @n8n-io/ai
packages/cli/src/services/ai-usage.service.ts @n8n-io/ai
packages/cli/src/services/ai-workflow-builder.service.ts @n8n-io/ai
packages/cli/src/services/annotation-tag.service.ee.ts @n8n-io/ai
packages/cli/src/services/folder.service.ts @n8n-io/adore
packages/cli/src/services/tag.service.ts @n8n-io/adore
packages/cli/src/services/cta.service.ts @n8n-io/adore
packages/cli/src/services/dynamic-templates.service.ts @n8n-io/adore
packages/cli/src/services/frontend.service.ts @n8n-io/adore
packages/cli/src/services/banner.service.ts @n8n-io/adore
packages/cli/src/services/project.service.ee.ts @n8n-io/ligo
packages/cli/src/services/workflow-statistics.service.ts @n8n-io/ligo
packages/cli/src/services/export.service.ts @n8n-io/ligo
packages/cli/src/services/import.service.ts @n8n-io/ligo
packages/cli/src/services/ownership.service.ts @n8n-io/ligo
packages/cli/src/services/dynamic-node-parameters.service.ts @n8n-io/nodes
# Adore
packages/frontend/editor-ui/ @n8n-io/frontend
packages/frontend/editor-ui/src/features/ai/ @n8n-io/ai
packages/frontend/editor-ui/src/features/credentials/ @n8n-io/iam
packages/frontend/editor-ui/src/features/execution/ @n8n-io/ligo
packages/frontend/editor-ui/src/features/project-roles/ @n8n-io/iam
packages/frontend/editor-ui/src/features/integrations/ @n8n-io/nodes
packages/frontend/@n8n/design-system/ @n8n-io/design
packages/frontend/@n8n/stores/ @n8n-io/frontend
packages/frontend/@n8n/composables/ @n8n-io/frontend
packages/frontend/@n8n/rest-api-client/ @n8n-io/frontend
packages/frontend/@n8n/storybook/ @n8n-io/design
packages/frontend/@n8n/i18n/ @n8n-io/frontend
packages/@n8n/stylelint-config/ @n8n-io/qa-dx
# AI
packages/@n8n/instance-ai/ @n8n-io/instance-ai
packages/@n8n/nodes-langchain/ @n8n-io/ai
packages/@n8n/ai-utilities/ @n8n-io/ai
packages/@n8n/ai-node-sdk/ @n8n-io/ai
packages/@n8n/ai-workflow-builder.ee/ @n8n-io/ai
packages/@n8n/agents/ @n8n-io/ai
packages/frontend/@n8n/chat/ @n8n-io/ai
# Chat
packages/@n8n/chat-hub/ @n8n-io/ai
# Nodes
packages/@n8n/codemirror-lang/ @n8n-io/nodes
packages/@n8n/codemirror-lang-html/ @n8n-io/nodes
packages/@n8n/codemirror-lang-sql/ @n8n-io/nodes
packages/nodes-base/ @n8n-io/nodes
packages/@n8n/decorators/ @n8n-io/catalysts
packages/node-dev/ @n8n-io/nodes
packages/@n8n/create-node/ @n8n-io/nodes
packages/@n8n/node-cli/ @n8n-io/nodes
packages/@n8n/imap/ @n8n-io/iam
packages/@n8n/syslog-client/ @n8n-io/iam
packages/@n8n/scan-community-package/ @n8n-io/nodes
packages/@n8n/eslint-plugin-community-nodes/ @n8n-io/nodes
packages/@n8n/computer-use/ @n8n-io/nodes
packages/@n8n/local-gateway/ @n8n-io/nodes
packages/@n8n/mcp-browser/ @n8n-io/nodes
packages/@n8n/mcp-browser-extension/ @n8n-io/nodes
# IAM
packages/@n8n/permissions/ @n8n-io/iam
packages/@n8n/client-oauth2/ @n8n-io/iam
# LiGo
packages/extensions/insights/ @n8n-io/ligo
# CI/CD
.github/ @n8n-io/qa-dx
docker/ @n8n-io/qa-dx
# QA
packages/testing/ @n8n-io/qa-dx
packages/@n8n/benchmark/ @n8n-io/qa-dx
packages/@n8n/vitest-config/ @n8n-io/qa-dx

12
.github/WORKFLOWS.md vendored
View File

@ -242,8 +242,7 @@ CALLER REUSABLE WORKFLOW
ci-pull-requests.yml
├──────────────────────────▶ test-unit-reusable.yml
├──────────────────────────▶ test-linting-reusable.yml
├──────────────────────────▶ test-e2e-ci-reusable.yml
│ └──────────▶ test-e2e-reusable.yml
├──────────────────────────▶ test-e2e-reusable.yml
└──────────────────────────▶ sec-ci-reusable.yml
└──────────▶ sec-poutine-reusable.yml
@ -260,8 +259,7 @@ test-workflows-nightly.yml
└──────────────────────────▶ test-workflows-callable.yml
test-e2e-vm-expressions-nightly.yml
└──────────────────────────▶ test-e2e-ci-reusable.yml
└──────────▶ test-e2e-reusable.yml
└──────────────────────────▶ test-e2e-reusable.yml
PR Comment Dispatchers (triggered by /command in PR comments):
test-workflows-pr-comment.yml
@ -421,8 +419,6 @@ Workflows with `workflow_call` trigger:
| `test-unit-reusable.yml` | `ref`, `nodeVersion`, `collectCoverage` | Unit tests |
| `test-linting-reusable.yml` | `ref`, `nodeVersion` | ESLint |
| `test-e2e-reusable.yml` | `branch`, `test-mode`, `shards`, `runner` | Core E2E executor |
| `test-e2e-ci-reusable.yml` | `branch` | E2E orchestrator |
| `test-e2e-docker-pull-reusable.yml`| `branch`, `n8n_version` | E2E with pulled image |
| `test-workflows-callable.yml` | `git_ref`, `compare_schemas` | Workflow tests |
| `docker-build-push.yml` | `n8n_version`, `release_type`, `push_enabled` | Docker build |
| `sec-ci-reusable.yml` | `ref` | Security orchestrator |
@ -491,7 +487,7 @@ Team ownership mappings in `CODEOWNERS`:
| `ubuntu-latest` | 2 | Simple jobs, fork PR E2E |
| `blacksmith-2vcpu-ubuntu-2204` | 2 | Standard builds, E2E shards |
| `blacksmith-4vcpu-ubuntu-2204` | 4 | Unit tests, typecheck, lint |
| `blacksmith-8vcpu-ubuntu-2204` | 8 | E2E coverage (weekly) |
| `blacksmith-8vcpu-ubuntu-2204` | 8 | Heavy parallel workloads |
| `blacksmith-4vcpu-ubuntu-2204-arm` | 4 | ARM64 Docker builds |
### Selection Guidelines
@ -504,7 +500,7 @@ Team ownership mappings in `CODEOWNERS`:
**`blacksmith-4vcpu-ubuntu-2204`** - Unit tests (parallelized), linting (parallel file processing), typechecking (CPU-intensive), E2E test shards
**`blacksmith-8vcpu-ubuntu-2204`** - Heavy parallel workloads, full E2E coverage runs
**`blacksmith-8vcpu-ubuntu-2204`** - Heavy parallel workloads
### Runner Provider Toggle

View File

@ -0,0 +1,51 @@
# Builds the n8n and runners CI test images (n8nio/n8n:local +
# n8nio/runners:local) and caches the tarball under a SHA-derived key so
# downstream jobs in the same workflow run can restore it via
# load-n8n-docker.
#
# Cache-aware: if the tarball for this SHA is already cached (e.g. a parent
# workflow ran prepare-docker earlier), the build step is skipped and this
# action becomes a no-op.
name: 'Build n8n CI Docker image'
description: 'Builds n8nio/n8n + n8nio/runners test images and publishes them as a SHA-keyed cache tarball for downstream shards.'
inputs:
build-variant:
description: 'standard or coverage. Coverage uses build:docker:coverage.'
required: false
default: 'standard'
runs:
using: 'composite'
steps:
- name: Check cache for existing image
id: cache-check
uses: actions/cache/restore@640a1c2554105b57832a23eea0b4672fc7a790d5 # v4.2.3
with:
key: n8n-docker-image-${{ github.sha }}
path: /tmp/n8n-image.tar.zst
lookup-only: true
- name: Build Docker image
if: steps.cache-check.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-nodejs
with:
build-command: ${{ inputs.build-variant == 'coverage' && 'pnpm build:docker:coverage' || 'pnpm build:docker' }}
enable-docker-cache: true
env:
INCLUDE_TEST_CONTROLLER: 'true'
- name: Save image tarball
if: steps.cache-check.outputs.cache-hit != 'true'
shell: bash
run: |
docker save n8nio/n8n:local n8nio/runners:local | zstd -T0 -3 -o /tmp/n8n-image.tar.zst
ls -lh /tmp/n8n-image.tar.zst
- name: Publish image tarball to cache
if: steps.cache-check.outputs.cache-hit != 'true'
uses: actions/cache/save@640a1c2554105b57832a23eea0b4672fc7a790d5 # v4.2.3
with:
key: n8n-docker-image-${{ github.sha }}
path: /tmp/n8n-image.tar.zst

View File

@ -1,6 +1,10 @@
import { describe, it } from 'node:test';
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { matchGlob, parseFilters, evaluateFilter, runValidate } from '../ci-filter.mjs';
import { execFileSync } from 'node:child_process';
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { matchGlob, parseFilters, evaluateFilter, runValidate, getChangedFiles, getMergeBase } from '../ci-filter.mjs';
// --- matchGlob ---
@ -172,6 +176,70 @@ describe('evaluateFilter', () => {
});
});
// --- getChangedFiles + getMergeBase (integration, exercises real git) ---
describe('getChangedFiles', () => {
const repoDir = mkdtempSync(join(tmpdir(), 'ci-filter-'));
const remoteDir = mkdtempSync(join(tmpdir(), 'ci-filter-remote-'));
const originalCwd = process.cwd();
const git = (args: string[], cwd: string = repoDir) =>
execFileSync('git', args, { cwd, stdio: 'pipe' }).toString().trim();
before(() => {
// Bare remote so the action's `git fetch origin <ref>` works
execFileSync('git', ['init', '--bare', '-b', 'main', remoteDir], { stdio: 'pipe' });
git(['init', '-b', 'main'], repoDir);
git(['config', 'user.email', 'test@test.local']);
git(['config', 'user.name', 'test']);
git(['remote', 'add', 'origin', remoteDir]);
// Common ancestor commit
writeFileSync(join(repoDir, 'shared.ts'), 'shared\n');
git(['add', '.']);
git(['commit', '-m', 'root']);
git(['push', 'origin', 'main']);
// PR branches off main, adds a file
git(['checkout', '-b', 'pr-branch']);
writeFileSync(join(repoDir, 'pr-only.ts'), 'pr\n');
git(['add', '.']);
git(['commit', '-m', 'PR change']);
// Master drifts forward, modifying shared.ts (the pre-fix bug surface)
git(['checkout', 'main']);
writeFileSync(join(repoDir, 'shared.ts'), 'shared\ndrift-from-master\n');
git(['commit', '-am', 'master moves']);
git(['push', 'origin', 'main']);
// Sit on the PR branch as if running CI
git(['checkout', 'pr-branch']);
process.chdir(repoDir);
});
after(() => {
process.chdir(originalCwd);
rmSync(repoDir, { recursive: true, force: true });
rmSync(remoteDir, { recursive: true, force: true });
});
it('returns only PR-introduced files (master drift does not pollute)', () => {
const changed = getChangedFiles('main');
assert.deepEqual(changed, ['pr-only.ts']);
});
it('getMergeBase returns the common ancestor commit', () => {
const mergeBase = getMergeBase();
assert.match(mergeBase, /^[a-f0-9]{40}$/);
const expected = git(['merge-base', 'FETCH_HEAD', 'HEAD']);
assert.equal(mergeBase, expected);
});
it('rejects unsafe base refs', () => {
assert.throws(() => getChangedFiles('main; rm -rf /'), /Unsafe/);
assert.throws(() => getChangedFiles('main$evil'), /Unsafe/);
});
});
// --- runValidate ---
describe('runValidate', () => {

View File

@ -24,6 +24,15 @@ outputs:
results:
description: 'JSON object: { "filter-name": true/false }'
value: ${{ steps.run.outputs.results }}
changed-files:
description: 'Newline-separated list of changed files (filter mode only)'
value: ${{ steps.run.outputs.changed-files }}
base-ref:
description: 'Resolved base ref used for the diff (filter mode only)'
value: ${{ steps.run.outputs.base-ref }}
merge-base:
description: 'Merge-base SHA between FETCH_HEAD and HEAD (filter mode only)'
value: ${{ steps.run.outputs.merge-base }}
runs:
using: 'composite'

View File

@ -98,14 +98,30 @@ export function getChangedFiles(baseRef) {
if (!SAFE_REF.test(baseRef)) {
throw new Error(`Unsafe base ref: "${baseRef}"`);
}
execSync(`git fetch --depth=1 origin ${baseRef}`, { stdio: 'pipe' });
const output = execSync('git diff --name-only FETCH_HEAD HEAD', { encoding: 'utf-8' });
// Deepen the fetch so the merge base is reachable from this shallow clone.
// A 2-dot diff (FETCH_HEAD HEAD) reports anything that differs in either
// direction, so files added to base-branch after the PR diverged show up as
// "changed" — spuriously triggering path-filtered jobs. The merge base
// scopes the diff to PR-only changes.
execSync(`git fetch --no-tags --prune --deepen=200 origin ${baseRef}`, { stdio: 'pipe' });
const output = execSync('git diff --name-only --merge-base FETCH_HEAD HEAD', {
encoding: 'utf-8',
});
return output
.split('\n')
.map((f) => f.trim())
.filter(Boolean);
}
/**
* Resolve the merge-base SHA between FETCH_HEAD and HEAD.
* Used to give downstream tools (e.g. janitor's AST diff) a stable, PR-only
* comparison point that doesn't drift when the base branch moves forward.
*/
export function getMergeBase() {
return execSync('git merge-base FETCH_HEAD HEAD', { encoding: 'utf-8' }).trim();
}
// --- Filter evaluation ---
/**
@ -155,7 +171,9 @@ export function runFilter() {
const filters = parseFilters(filtersInput);
const changedFiles = getChangedFiles(baseRef);
const mergeBase = getMergeBase();
console.log(`Merge base: ${mergeBase}`);
console.log(`Changed files (${changedFiles.length}):`);
for (const f of changedFiles) {
console.log(` ${f}`);
@ -170,6 +188,9 @@ export function runFilter() {
}
setOutput('results', JSON.stringify(results));
setOutput('changed-files', changedFiles.join('\n'));
setOutput('base-ref', baseRef);
setOutput('merge-base', mergeBase);
}
// --- Mode: validate ---

View File

@ -39,10 +39,13 @@ runs:
- name: Login to DockerHub
if: inputs.login-dockerhub == 'true'
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
username: ${{ inputs.dockerhub-username }}
password: ${{ inputs.dockerhub-password }}
shell: bash
env:
DOCKER_USER: ${{ inputs.dockerhub-username }}
DOCKER_PASS: ${{ inputs.dockerhub-password }}
run: |
node .github/scripts/retry.mjs --attempts 3 --delay 10 \
'echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin'
- name: Login to DHI Registry
if: inputs.login-dhi == 'true'

View File

@ -0,0 +1,23 @@
# Restores the n8n + runners image tarball (produced by build-n8n-docker
# under the SHA-derived cache key) and loads both images into the local
# docker daemon.
#
# After this action runs, `n8nio/n8n:local` and `n8nio/runners:local` are
# present on the runner.
name: 'Load n8n Docker images from cache'
description: 'Restores the zstd-compressed n8n + runners image tarball from the SHA-keyed GHA cache and loads both images into the local docker daemon.'
runs:
using: 'composite'
steps:
- name: Restore image tarball from cache
uses: actions/cache/restore@640a1c2554105b57832a23eea0b4672fc7a790d5 # v4.2.3
with:
key: n8n-docker-image-${{ github.sha }}
path: /tmp/n8n-image.tar.zst
fail-on-cache-miss: true
- name: Load n8n and runners images into docker
shell: bash
run: zstd -d -c /tmp/n8n-image.tar.zst | docker load

View File

@ -45,13 +45,19 @@ runs:
mkdir -p "$PNPM_STORE_PATH"
fi
- name: Install Aikido SafeChain
if: runner.os != 'Windows'
- name: Configure SafeChain
shell: bash
run: |
VERSION="1.4.1"
EXPECTED_SHA256="628235987175072a4255aa3f5f0128f31795b63970f1970ae8a04d07bf8527b0"
node .github/scripts/retry.mjs --attempts 3 --delay 10 \
"curl -fsSL -o install-safe-chain.sh https://github.com/AikidoSec/safe-chain/releases/download/${VERSION}/install-safe-chain.sh"
# SafeChain only reads configs from this directory https://github.com/AikidoSec/safe-chain#configuration-options-1
mkdir -p "$HOME/.safe-chain"
cp "${{ github.action_path }}/safe-chain.config.json" "$HOME/.safe-chain/config.json"
- name: Install Aikido SafeChain
run: |
VERSION="1.5.1"
EXPECTED_SHA256="7c910fff717649c86cc8ca960e6c054d3734da2d660050e3bcfc54029e3b485b"
node .github/scripts/retry.mjs --attempts 3 --delay 10 -- \
curl -fsSL -o install-safe-chain.sh "https://github.com/AikidoSec/safe-chain/releases/download/${VERSION}/install-safe-chain.sh"
echo "${EXPECTED_SHA256} install-safe-chain.sh" | sha256sum -c -
sh install-safe-chain.sh --ci
rm install-safe-chain.sh
@ -59,13 +65,10 @@ runs:
- name: Install Dependencies
if: ${{ inputs.install-command != '' }}
env:
INSTALL_COMMAND: ${{ inputs.install-command }}
run: |
${{ inputs.install-command }}
shell: bash
- name: Disable safe-chain
if: runner.os != 'Windows'
run: safe-chain teardown
$INSTALL_COMMAND
shell: bash
- name: Configure Turborepo Cache
@ -81,8 +84,10 @@ runs:
- name: Build Project
if: ${{ inputs.build-command != '' }}
env:
BUILD_COMMAND: ${{ inputs.build-command }}
run: |
${{ inputs.build-command }} --summarize
$BUILD_COMMAND --summarize
node .github/scripts/send-build-stats.mjs || true
node .github/scripts/send-docker-stats.mjs || true
shell: bash

View File

@ -0,0 +1,16 @@
{
"npm": {
"minimumPackageAgeExclusions": [
"@n8n/*",
"@n8n_io/*",
"n8n",
"n8n-containers",
"n8n-core",
"n8n-editor-ui",
"n8n-node-dev",
"n8n-nodes-base",
"n8n-playwright",
"n8n-workflow"
]
}
}

View File

@ -1,4 +1,5 @@
import semver from 'semver';
import { parse } from 'yaml';
import { writeFile, readFile } from 'fs/promises';
import { resolve } from 'path';
import child_process from 'child_process';
@ -7,14 +8,19 @@ import assert from 'assert';
const exec = promisify(child_process.exec);
function generateExperimentalVersion(currentVersion) {
/**
* @param {string | semver.SemVer} currentVersion
*/
export function generateExperimentalVersion(currentVersion) {
const parsed = semver.parse(currentVersion);
if (!parsed) throw new Error(`Invalid version: ${currentVersion}`);
// Check if it's already an experimental version
if (parsed.prerelease.length > 0 && parsed.prerelease[0] === 'exp') {
const minor = parsed.prerelease[1] || 0;
const minorInt = typeof minor === 'string' ? parseInt(minor) : minor;
// Increment the experimental minor version
const expMinor = (parsed.prerelease[1] || 0) + 1;
const expMinor = minorInt + 1;
return `${parsed.major}.${parsed.minor}.${parsed.patch}-exp.${expMinor}`;
}
@ -22,96 +28,267 @@ function generateExperimentalVersion(currentVersion) {
return `${parsed.major}.${parsed.minor}.${parsed.patch}-exp.0`;
}
const rootDir = process.cwd();
const releaseType = process.env.RELEASE_TYPE;
assert.match(releaseType, /^(patch|minor|major|experimental|premajor)$/, 'Invalid RELEASE_TYPE');
// TODO: if releaseType is `auto` determine release type based on the changelog
const lastTag = (await exec('git describe --tags --match "n8n@*" --abbrev=0')).stdout.trim();
const packages = JSON.parse(
(
await exec(
`pnpm ls -r --only-projects --json | jq -r '[.[] | { name: .name, version: .version, path: .path, private: .private}]'`,
)
).stdout,
);
const packageMap = {};
for (let { name, path, version, private: isPrivate } of packages) {
if (isPrivate && path !== rootDir) continue;
if (path === rootDir) name = 'monorepo-root';
const isDirty = await exec(`git diff --quiet HEAD ${lastTag} -- ${path}`)
.then(() => false)
.catch((error) => true);
packageMap[name] = { path, isDirty, version };
/**
* @param {{ pnpm?: { overrides?: Record<string, string> }, overrides?: Record<string, string> }} pkg
* @returns {Record<string, string>}
*/
export function getOverrides(pkg) {
return { ...pkg.pnpm?.overrides, ...pkg.overrides };
}
assert.ok(
Object.values(packageMap).some(({ isDirty }) => isDirty),
'No changes found since the last release',
);
// Propagate isDirty transitively: if a package's dependency will be bumped,
// that package also needs a bump (e.g. design-system → editor-ui → cli).
const depsByPackage = {};
for (const packageName in packageMap) {
const packageFile = resolve(packageMap[packageName].path, 'package.json');
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
depsByPackage[packageName] = Object.keys(packageJson.dependencies || {});
/**
* @param {string} content
* @returns {Record<string, unknown>}
*/
export function parseWorkspaceYaml(content) {
try {
return /** @type {Record<string, unknown>} */ (parse(content) ?? {});
} catch {
return {};
}
}
let changed = true;
while (changed) {
changed = false;
for (const packageName in packageMap) {
/**
* @param {Record<string, unknown>} ws
* @returns {Map<string, Record<string, string>>}
*/
export function getCatalogs(ws) {
const result = new Map();
if (ws.catalog) {
result.set('default', /** @type {Record<string,string>} */ (ws.catalog));
}
for (const [name, entries] of Object.entries(ws.catalogs ?? {})) {
result.set(name, entries);
}
return result;
}
/**
* @param {Record<string, string>} currentOverrides
* @param {Record<string, string>} previousOverrides
* @returns {Set<string>}
*/
export function computeChangedOverrides(currentOverrides, previousOverrides) {
return new Set(
Object.keys({ ...currentOverrides, ...previousOverrides }).filter(
(k) => currentOverrides[k] !== previousOverrides[k],
),
);
}
/**
* @param {Map<string, Record<string, string>>} currentCatalogs
* @param {Map<string, Record<string, string>>} previousCatalogs
* @returns {Map<string, Set<string>>}
*/
export function computeChangedCatalogEntries(currentCatalogs, previousCatalogs) {
const changedCatalogEntries = new Map();
for (const catalogName of new Set([...currentCatalogs.keys(), ...previousCatalogs.keys()])) {
const current = currentCatalogs.get(catalogName) ?? {};
const previous = previousCatalogs.get(catalogName) ?? {};
const changedDeps = new Set(
Object.keys({ ...current, ...previous }).filter((dep) => current[dep] !== previous[dep]),
);
if (changedDeps.size > 0) {
changedCatalogEntries.set(catalogName, changedDeps);
}
}
return changedCatalogEntries;
}
/**
* Mark packages as dirty if any dep had a root-level override or catalog version change.
* Mutates packageMap in place.
*
* @param {Record<string, { isDirty: boolean }>} packageMap
* @param {Record<string, Record<string, string>>} depsByPackage
* @param {Set<string>} changedOverrides
* @param {Map<string, Set<string>>} changedCatalogEntries
*/
export function markDirtyByRootChanges(
packageMap,
depsByPackage,
changedOverrides,
changedCatalogEntries,
) {
for (const [packageName, deps] of Object.entries(depsByPackage)) {
if (packageMap[packageName].isDirty) continue;
if (depsByPackage[packageName].some((dep) => packageMap[dep]?.isDirty)) {
packageMap[packageName].isDirty = true;
changed = true;
for (const [dep, specifier] of Object.entries(deps)) {
if (changedOverrides.has(dep)) {
packageMap[packageName].isDirty = true;
break;
}
if (typeof specifier === 'string' && specifier.startsWith('catalog:')) {
const catalogName = specifier === 'catalog:' ? 'default' : specifier.slice(8);
if (changedCatalogEntries.get(catalogName)?.has(dep)) {
packageMap[packageName].isDirty = true;
break;
}
}
}
}
}
// Keep the monorepo version up to date with the released version
packageMap['monorepo-root'].version = packageMap['n8n'].version;
/**
* Propagate isDirty transitively: if a package's dependency will be bumped,
* that package also needs a bump. Mutates packageMap in place.
*
* @param {Record<string, { isDirty: boolean }>} packageMap
* @param {Record<string, Record<string, string>>} depsByPackage
*/
export function propagateDirtyTransitively(packageMap, depsByPackage) {
let changed = true;
while (changed) {
changed = false;
for (const packageName in packageMap) {
if (packageMap[packageName].isDirty) continue;
if (Object.keys(depsByPackage[packageName]).some((dep) => packageMap[dep]?.isDirty)) {
packageMap[packageName].isDirty = true;
changed = true;
}
}
}
}
for (const packageName in packageMap) {
const { path, version, isDirty } = packageMap[packageName];
const packageFile = resolve(path, 'package.json');
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
const dependencyIsDirty = Object.keys(packageJson.dependencies || {}).some(
(dependencyName) => packageMap[dependencyName]?.isDirty,
);
let newVersion = version;
if (isDirty || dependencyIsDirty) {
switch (releaseType) {
case 'experimental':
newVersion = generateExperimentalVersion(version);
break;
case 'premajor':
newVersion = semver.inc(
/**
* @param {string} version
* @param {import('semver').ReleaseType | 'experimental'} releaseType
* @returns {string}
*/
export function computeNewVersion(version, releaseType) {
switch (releaseType) {
case 'experimental':
return generateExperimentalVersion(version);
case 'premajor':
return /** @type {string} */ (
semver.inc(
version,
version.includes('-rc.') ? 'prerelease' : 'premajor',
undefined,
'rc',
);
break;
default:
newVersion = semver.inc(version, releaseType);
break;
}
)
);
default:
return /** @type {string} */ (semver.inc(version, releaseType));
}
packageJson.version = packageMap[packageName].nextVersion = newVersion;
await writeFile(packageFile, JSON.stringify(packageJson, null, 2) + '\n');
}
console.log(packageMap['n8n'].nextVersion);
async function bumpVersions() {
const rootDir = process.cwd();
const releaseType = /** @type { import('semver').ReleaseType | "experimental" } */ (
process.env.RELEASE_TYPE
);
assert.match(releaseType, /^(patch|minor|major|experimental|premajor)$/, 'Invalid RELEASE_TYPE');
// TODO: if releaseType is `auto` determine release type based on the changelog
const lastTag = (await exec('git describe --tags --match "n8n@*" --abbrev=0')).stdout.trim();
const packages = JSON.parse(
(
await exec(
`pnpm ls -r --only-projects --json | jq -r '[.[] | { name: .name, version: .version, path: .path, private: .private}]'`,
)
).stdout,
);
/** @type {Record<string, { path: string, isDirty: boolean, version: string, nextVersion?: string }>} */
const packageMap = {};
for (let { name, path, version, private: isPrivate } of packages) {
if (isPrivate && path !== rootDir) {
continue;
}
if (path === rootDir) {
name = 'monorepo-root';
}
const isDirty = await exec(`git diff --quiet HEAD ${lastTag} -- ${path}`)
.then(() => false)
.catch(() => true);
packageMap[name] = { path, isDirty, version };
}
assert.ok(
Object.values(packageMap).some(({ isDirty }) => isDirty),
'No changes found since the last release',
);
// Propagate isDirty transitively: if a package's dependency will be bumped,
// that package also needs a bump (e.g. design-system → editor-ui → cli).
// Detect root-level changes that affect resolved dep versions without touching individual
// package.json files: pnpm.overrides (applies to all specifiers)
// and pnpm-workspace.yaml catalog entries (applies only to deps using a "catalog:…" specifier).
const rootPkgJson = JSON.parse(await readFile(resolve(rootDir, 'package.json'), 'utf-8'));
const rootPkgJsonAtTag = await exec(`git show ${lastTag}:package.json`)
.then(({ stdout }) => JSON.parse(stdout))
.catch(() => ({}));
const changedOverrides = computeChangedOverrides(
getOverrides(rootPkgJson),
getOverrides(rootPkgJsonAtTag),
);
const workspaceYaml = parseWorkspaceYaml(
await readFile(resolve(rootDir, 'pnpm-workspace.yaml'), 'utf-8').catch(() => ''),
);
const workspaceYamlAtTag = parseWorkspaceYaml(
await exec(`git show ${lastTag}:pnpm-workspace.yaml`)
.then(({ stdout }) => stdout)
.catch(() => ''),
);
const changedCatalogEntries = computeChangedCatalogEntries(
getCatalogs(workspaceYaml),
getCatalogs(workspaceYamlAtTag),
);
// Store full dep objects (with specifiers) so we can inspect "catalog:…" values below.
/** @type {Record<string, Record<string, string>>} */
const depsByPackage = {};
for (const packageName in packageMap) {
const packageFile = resolve(packageMap[packageName].path, 'package.json');
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
depsByPackage[packageName] = /** @type {Record<string,string>} */ (
packageJson.dependencies ?? {}
);
}
// Mark packages dirty if any dep had a root-level override or catalog version change.
markDirtyByRootChanges(packageMap, depsByPackage, changedOverrides, changedCatalogEntries);
propagateDirtyTransitively(packageMap, depsByPackage);
// Keep the monorepo version up to date with the released version
packageMap['monorepo-root'].version = packageMap['n8n'].version;
for (const packageName in packageMap) {
const { path, version, isDirty } = packageMap[packageName];
const packageFile = resolve(path, 'package.json');
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
const dependencyIsDirty = Object.keys(packageJson.dependencies || {}).some(
(dependencyName) => packageMap[dependencyName]?.isDirty,
);
let newVersion = version;
if (isDirty || dependencyIsDirty) {
newVersion = computeNewVersion(version, releaseType);
}
packageJson.version = packageMap[packageName].nextVersion = newVersion;
await writeFile(packageFile, JSON.stringify(packageJson, null, 2) + '\n');
}
console.log(packageMap['n8n'].nextVersion);
}
// only run when executed directly, not when imported by tests
if (import.meta.url === `file://${process.argv[1]}`) {
bumpVersions();
}

380
.github/scripts/bump-versions.test.mjs vendored Normal file
View File

@ -0,0 +1,380 @@
/**
* Run these tests with:
*
* node --test ./.github/scripts/bump-versions.test.mjs
*/
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
generateExperimentalVersion,
getOverrides,
parseWorkspaceYaml,
getCatalogs,
computeChangedOverrides,
computeChangedCatalogEntries,
markDirtyByRootChanges,
propagateDirtyTransitively,
computeNewVersion,
} from './bump-versions.mjs';
describe('generateExperimentalVersion', () => {
it('creates -exp.0 from a stable version', () => {
assert.equal(generateExperimentalVersion('1.2.3'), '1.2.3-exp.0');
});
it('increments exp minor when already at exp.0', () => {
assert.equal(generateExperimentalVersion('1.2.3-exp.0'), '1.2.3-exp.1');
});
it('increments exp minor when already at exp.5', () => {
assert.equal(generateExperimentalVersion('1.2.3-exp.5'), '1.2.3-exp.6');
});
it('creates -exp.0 from a version with a different pre-release tag', () => {
assert.equal(generateExperimentalVersion('1.2.3-beta.1'), '1.2.3-exp.0');
});
it('handles multi-digit version numbers', () => {
assert.equal(generateExperimentalVersion('10.20.30'), '10.20.30-exp.0');
});
it('throws on an invalid version string', () => {
assert.throws(() => generateExperimentalVersion('not-a-version'), /Invalid version/);
});
});
describe('getOverrides', () => {
it('returns empty object when no overrides exist', () => {
assert.deepEqual(getOverrides({}), {});
});
it('returns pnpm.overrides when only pnpm.overrides is set', () => {
assert.deepEqual(getOverrides({ pnpm: { overrides: { lodash: '^4.0.0' } } }), {
lodash: '^4.0.0',
});
});
it('returns overrides when only top-level overrides is set', () => {
assert.deepEqual(getOverrides({ overrides: { lodash: '^4.0.0' } }), { lodash: '^4.0.0' });
});
it('merges both fields with top-level overrides taking precedence for the same key', () => {
assert.deepEqual(
getOverrides({
pnpm: { overrides: { lodash: '^3.0.0', underscore: '^1.0.0' } },
overrides: { lodash: '^4.0.0' },
}),
{ lodash: '^4.0.0', underscore: '^1.0.0' },
);
});
});
describe('parseWorkspaceYaml', () => {
it('parses valid YAML into an object', () => {
assert.deepEqual(parseWorkspaceYaml('catalog:\n lodash: "^4.0.0"'), {
catalog: { lodash: '^4.0.0' },
});
});
it('returns empty object for an empty string', () => {
assert.deepEqual(parseWorkspaceYaml(''), {});
});
it('returns empty object for invalid YAML', () => {
assert.deepEqual(parseWorkspaceYaml(': - invalid: [yaml}'), {});
});
});
describe('getCatalogs', () => {
it('returns empty map when no catalog or catalogs field exists', () => {
assert.equal(getCatalogs({}).size, 0);
});
it('returns a "default" entry for the top-level catalog field', () => {
const result = getCatalogs({ catalog: { lodash: '^4.0.0' } });
assert.equal(result.size, 1);
assert.deepEqual(result.get('default'), { lodash: '^4.0.0' });
});
it('returns named entries from the catalogs field', () => {
const result = getCatalogs({ catalogs: { react18: { react: '^18.0.0' } } });
assert.equal(result.size, 1);
assert.deepEqual(result.get('react18'), { react: '^18.0.0' });
});
it('returns both default and named catalog entries when both fields are present', () => {
const result = getCatalogs({
catalog: { lodash: '^4.0.0' },
catalogs: { react18: { react: '^18.0.0' } },
});
assert.equal(result.size, 2);
assert.deepEqual(result.get('default'), { lodash: '^4.0.0' });
assert.deepEqual(result.get('react18'), { react: '^18.0.0' });
});
});
describe('computeChangedOverrides', () => {
it('returns empty set when nothing changed', () => {
assert.equal(computeChangedOverrides({ lodash: '^4' }, { lodash: '^4' }).size, 0);
});
it('detects an added override', () => {
const result = computeChangedOverrides({ lodash: '^4' }, {});
assert.ok(result.has('lodash'));
});
it('detects a removed override', () => {
const result = computeChangedOverrides({}, { lodash: '^4' });
assert.ok(result.has('lodash'));
});
it('detects a changed override value', () => {
const result = computeChangedOverrides({ lodash: '^4' }, { lodash: '^3' });
assert.ok(result.has('lodash'));
});
it('does not include unchanged overrides', () => {
const result = computeChangedOverrides(
{ lodash: '^4', underscore: '^1' },
{ lodash: '^4', underscore: '^1' },
);
assert.equal(result.size, 0);
});
it('handles mixed changed and unchanged overrides', () => {
const result = computeChangedOverrides(
{ lodash: '^4', underscore: '^2' },
{ lodash: '^4', underscore: '^1' },
);
assert.equal(result.size, 1);
assert.ok(result.has('underscore'));
assert.ok(!result.has('lodash'));
});
});
describe('computeChangedCatalogEntries', () => {
it('returns empty map when nothing changed', () => {
const current = new Map([['default', { lodash: '^4' }]]);
const previous = new Map([['default', { lodash: '^4' }]]);
assert.equal(computeChangedCatalogEntries(current, previous).size, 0);
});
it('detects an added dep in a catalog', () => {
const current = new Map([['default', { lodash: '^4' }]]);
const previous = new Map([['default', {}]]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('default')?.has('lodash'));
});
it('detects a removed dep from a catalog', () => {
const current = new Map([['default', {}]]);
const previous = new Map([['default', { lodash: '^4' }]]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('default')?.has('lodash'));
});
it('detects a changed dep version in a catalog', () => {
const current = new Map([['default', { lodash: '^4' }]]);
const previous = new Map([['default', { lodash: '^3' }]]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('default')?.has('lodash'));
});
it('detects changes in a named catalog', () => {
const current = new Map([['react18', { react: '^18' }]]);
const previous = new Map([['react18', { react: '^17' }]]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('react18')?.has('react'));
});
it('detects a newly added catalog', () => {
const current = new Map([['newCatalog', { lodash: '^4' }]]);
const previous = new Map();
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('newCatalog')?.has('lodash'));
});
it('detects a removed catalog', () => {
const current = new Map();
const previous = new Map([['oldCatalog', { lodash: '^4' }]]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.get('oldCatalog')?.has('lodash'));
});
it('does not include a catalog that has no changed entries', () => {
const current = new Map([
['default', { lodash: '^4' }],
['react18', { react: '^18' }],
]);
const previous = new Map([
['default', { lodash: '^3' }],
['react18', { react: '^18' }],
]);
const result = computeChangedCatalogEntries(current, previous);
assert.ok(result.has('default'));
assert.ok(!result.has('react18'));
});
});
describe('markDirtyByRootChanges', () => {
it('marks a package dirty when its dep appears in changedOverrides', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { lodash: '^4' } };
markDirtyByRootChanges(packageMap, depsByPackage, new Set(['lodash']), new Map());
assert.ok(packageMap['pkg-a'].isDirty);
});
it('skips already-dirty packages', () => {
const packageMap = { 'pkg-a': { isDirty: true } };
// No deps, but package is already dirty — should not throw or change state
const depsByPackage = { 'pkg-a': {} };
markDirtyByRootChanges(packageMap, depsByPackage, new Set(['lodash']), new Map());
assert.ok(packageMap['pkg-a'].isDirty);
});
it('marks a package dirty when its dep uses "catalog:" (default catalog) and that entry changed', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { lodash: 'catalog:' } };
const changedCatalogEntries = new Map([['default', new Set(['lodash'])]]);
markDirtyByRootChanges(packageMap, depsByPackage, new Set(), changedCatalogEntries);
assert.ok(packageMap['pkg-a'].isDirty);
});
it('marks a package dirty when its dep uses "catalog:<name>" and that named catalog entry changed', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { react: 'catalog:react18' } };
const changedCatalogEntries = new Map([['react18', new Set(['react'])]]);
markDirtyByRootChanges(packageMap, depsByPackage, new Set(), changedCatalogEntries);
assert.ok(packageMap['pkg-a'].isDirty);
});
it('does not mark a package dirty when none of its deps changed', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { lodash: '^4' } };
markDirtyByRootChanges(packageMap, depsByPackage, new Set(['underscore']), new Map());
assert.ok(!packageMap['pkg-a'].isDirty);
});
it('does not mark a package dirty when a catalog: dep is in a catalog with no changes', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { lodash: 'catalog:' } };
const changedCatalogEntries = new Map([['default', new Set(['underscore'])]]);
markDirtyByRootChanges(packageMap, depsByPackage, new Set(), changedCatalogEntries);
assert.ok(!packageMap['pkg-a'].isDirty);
});
it('does not mark a package dirty when a catalog: dep is in a different catalog than the one that changed', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { react: 'catalog:react18' } };
const changedCatalogEntries = new Map([['default', new Set(['react'])]]);
markDirtyByRootChanges(packageMap, depsByPackage, new Set(), changedCatalogEntries);
assert.ok(!packageMap['pkg-a'].isDirty);
});
});
describe('propagateDirtyTransitively', () => {
it('does nothing when no packages are dirty', () => {
const packageMap = {
'pkg-a': { isDirty: false },
'pkg-b': { isDirty: false },
};
const depsByPackage = {
'pkg-a': { 'pkg-b': 'workspace:*' },
'pkg-b': {},
};
propagateDirtyTransitively(packageMap, depsByPackage);
assert.ok(!packageMap['pkg-a'].isDirty);
assert.ok(!packageMap['pkg-b'].isDirty);
});
it('propagates dirty state one level up the dependency chain', () => {
const packageMap = {
'pkg-a': { isDirty: false },
'pkg-b': { isDirty: true },
};
const depsByPackage = {
'pkg-a': { 'pkg-b': 'workspace:*' },
'pkg-b': {},
};
propagateDirtyTransitively(packageMap, depsByPackage);
assert.ok(packageMap['pkg-a'].isDirty);
});
it('propagates dirty state through multiple levels', () => {
const packageMap = {
'pkg-a': { isDirty: false },
'pkg-b': { isDirty: false },
'pkg-c': { isDirty: true },
};
const depsByPackage = {
'pkg-a': { 'pkg-b': 'workspace:*' },
'pkg-b': { 'pkg-c': 'workspace:*' },
'pkg-c': {},
};
propagateDirtyTransitively(packageMap, depsByPackage);
assert.ok(packageMap['pkg-b'].isDirty, 'pkg-b should be dirty (depends on dirty pkg-c)');
assert.ok(packageMap['pkg-a'].isDirty, 'pkg-a should be dirty (depends on dirty pkg-b)');
});
it('does not mark packages dirty when their deps are external (not in packageMap)', () => {
const packageMap = { 'pkg-a': { isDirty: false } };
const depsByPackage = { 'pkg-a': { lodash: '^4' } };
propagateDirtyTransitively(packageMap, depsByPackage);
assert.ok(!packageMap['pkg-a'].isDirty);
});
it('handles diamond dependency graphs without infinite loops', () => {
// pkg-a depends on pkg-b and pkg-c; both depend on pkg-d (dirty)
const packageMap = {
'pkg-a': { isDirty: false },
'pkg-b': { isDirty: false },
'pkg-c': { isDirty: false },
'pkg-d': { isDirty: true },
};
const depsByPackage = {
'pkg-a': { 'pkg-b': 'workspace:*', 'pkg-c': 'workspace:*' },
'pkg-b': { 'pkg-d': 'workspace:*' },
'pkg-c': { 'pkg-d': 'workspace:*' },
'pkg-d': {},
};
propagateDirtyTransitively(packageMap, depsByPackage);
assert.ok(packageMap['pkg-b'].isDirty);
assert.ok(packageMap['pkg-c'].isDirty);
assert.ok(packageMap['pkg-a'].isDirty);
});
});
describe('computeNewVersion', () => {
it('increments patch version', () => {
assert.equal(computeNewVersion('1.2.3', 'patch'), '1.2.4');
});
it('increments minor version (resets patch)', () => {
assert.equal(computeNewVersion('1.2.3', 'minor'), '1.3.0');
});
it('increments major version (resets minor and patch)', () => {
assert.equal(computeNewVersion('1.2.3', 'major'), '2.0.0');
});
it('creates -exp.0 from a stable version for experimental', () => {
assert.equal(computeNewVersion('1.2.3', 'experimental'), '1.2.3-exp.0');
});
it('increments exp minor for experimental when already an exp version', () => {
assert.equal(computeNewVersion('1.2.3-exp.0', 'experimental'), '1.2.3-exp.1');
});
it('creates a premajor rc version from a stable version', () => {
assert.equal(computeNewVersion('1.2.3', 'premajor'), '2.0.0-rc.0');
});
it('increments the rc prerelease number for premajor when already an rc version', () => {
assert.equal(computeNewVersion('2.0.0-rc.0', 'premajor'), '2.0.0-rc.1');
});
it('increments rc correctly across multiple premajor calls', () => {
assert.equal(computeNewVersion('2.0.0-rc.4', 'premajor'), '2.0.0-rc.5');
});
});

114
.github/scripts/cla/check-signatures.mjs vendored Normal file
View File

@ -0,0 +1,114 @@
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
//
// Collects unique commit authors for the PR (or for the commits a merge
// queue is about to land) and asks the n8n CLA service whether each one
// has signed. Surfaces three buckets to subsequent steps:
// - signed : verified contributors
// - unsigned : verified non-contributors (block the merge)
// - errored : CLA lookup failed (block the merge — fail-closed so we
// never green-light an unverified contribution)
//
// Commits whose author email is not linked to a GitHub account can't be
// looked up by login; they're surfaced separately as `unlinked`.
/**
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
* @typedef { import("@actions/github/lib/context").Context } Context
* @typedef { typeof import("@actions/core") } Core
*/
/**
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
*/
export default async function checkSignatures ({ github, context, core }) {
const { owner, repo } = context.repo;
const prNumber = process.env.PR_NUMBER;
const headSha = process.env.HEAD_SHA;
const baseSha = process.env.BASE_SHA;
const isMergeGroup = process.env.IS_MERGE_GROUP === 'true';
/** @type {Set<string>} */
const authors = new Set();
/** @type {Array<{sha: string, name: string, email: string}>} */
const unlinkedCommits = [];
/**
* @param {Array<any>} commits
*/
const collect = (commits) => {
for (const c of commits) {
// Bot-authored commits don't need a CLA; skip before the linked/unlinked split
// so they don't fall through to `unlinkedCommits` and fail `all_signed`.
if (c.author && c.author.type === 'Bot') continue;
if (c.author && c.author.login) {
authors.add(c.author.login);
} else if (c.commit && c.commit.author) {
unlinkedCommits.push({
sha: c.sha,
name: c.commit.author.name,
email: c.commit.author.email,
});
}
}
};
if (isMergeGroup) {
const { data: comparison } = await github.rest.repos.compareCommitsWithBasehead({
owner,
repo,
basehead: `${baseSha}...${headSha}`,
});
collect(comparison.commits || []);
} else if (prNumber) {
const commits = await github.paginate(github.rest.pulls.listCommits, {
owner,
repo,
pull_number: Number(prNumber),
per_page: 100,
});
collect(commits);
}
const loginList = [...authors];
core.info(`Contributors to check: ${loginList.join(', ') || '(none)'}`);
if (unlinkedCommits.length > 0) {
core.warning(
`${unlinkedCommits.length} commit(s) have an author email not linked to a GitHub account ` +
'and cannot be verified against the CLA service.',
);
}
/** @type {string[]} */
const signed = [];
/** @type {string[]} */
const unsigned = [];
/** @type {string[]} */
const errored = [];
for (const login of loginList) {
const url = `${process.env.CLA_API}?checkContributor=${encodeURIComponent(login)}`;
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (data && data.isContributor === true) {
signed.push(login);
} else {
unsigned.push(login);
}
} catch (e) {
core.warning(`CLA lookup failed for @${login}: ${e instanceof Error ? e.message : String(e)}`);
errored.push(login);
}
}
const blocking = [...unsigned, ...errored];
const allSigned = blocking.length === 0 && unlinkedCommits.length === 0;
core.setOutput('signed', signed.join(','));
core.setOutput('unsigned', unsigned.join(','));
core.setOutput('errored', errored.join(','));
core.setOutput('unlinked', JSON.stringify(unlinkedCommits));
core.setOutput('all_signed', String(allSigned));
}

83
.github/scripts/cla/manage-label.mjs vendored Normal file
View File

@ -0,0 +1,83 @@
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
//
// Adds the `cla-signed` label when every contributor has signed, and
// removes it otherwise. Idempotent: re-runs safely without duplicating
// the label or erroring if it's already in the desired state. Creates
// the label on first use so the workflow is self-contained.
/**
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
* @typedef { import("@actions/github/lib/context").Context } Context
* @typedef { typeof import("@actions/core") } Core
*/
const LABEL_NAME = 'cla-signed';
const LABEL_COLOR = '0e8a16'; // GitHub's standard green
const LABEL_DESCRIPTION = 'All contributors on this PR have signed the CLA';
/**
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
*/
export default async function manageClaLabel({ github, context, core }) {
const { owner, repo } = context.repo;
const issue_number = Number(process.env.PR_NUMBER);
const allSigned = process.env.ALL_SIGNED === 'true';
if (allSigned) {
// Make sure the label exists before trying to apply it — addLabels
// errors if the label is missing from the repo.
try {
await github.rest.issues.getLabel({ owner, repo, name: LABEL_NAME });
} catch (e) {
if (errorStatus(e) === 404) {
try {
await github.rest.issues.createLabel({
owner,
repo,
name: LABEL_NAME,
color: LABEL_COLOR,
description: LABEL_DESCRIPTION,
});
} catch (createErr) {
// 422 = race with a parallel run that just created it. Fine.
if (errorStatus(createErr) !== 422) throw createErr;
}
} else {
throw e;
}
}
await github.rest.issues.addLabels({
owner,
repo,
issue_number,
labels: [LABEL_NAME],
});
core.info(`Applied "${LABEL_NAME}" label to PR #${issue_number}`);
} else {
// 404 just means the label wasn't on the PR — nothing to undo.
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number,
name: LABEL_NAME,
});
core.info(`Removed "${LABEL_NAME}" label from PR #${issue_number}`);
} catch (e) {
if (errorStatus(e) !== 404) throw e;
}
}
}
/**
* Octokit's request errors carry an HTTP `status` field, but TypeScript
* sees catch parameters as `unknown`. This guard narrows safely.
* @param {unknown} e
* @returns {number | undefined}
*/
function errorStatus(e) {
return typeof e === 'object' && e !== null && 'status' in e && typeof e.status === 'number'
? e.status
: undefined;
}

View File

@ -0,0 +1,66 @@
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
//
// Translates the buckets emitted by check-signatures.mjs into a single
// commit status on the head SHA. The status `context` name is what a
// repository ruleset gates on; description and target_url are best-effort
// human signals.
//
// State mapping:
// - success: every contributor is signed and every commit author is linked
// - error : only failures were API lookup errors (transient)
// - failure: at least one contributor is verified unsigned, or commits
// have author emails not linked to a GitHub account
/**
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
* @typedef { import("@actions/github/lib/context").Context } Context
* @typedef { typeof import("@actions/core") } Core
*/
/**
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
*/
export default async function postFinalClaStatus({ github, context }) {
const allSigned = process.env.ALL_SIGNED === 'true';
const unsigned = (process.env.UNSIGNED ?? '').split(',').filter(Boolean);
const errored = (process.env.ERRORED ?? '').split(',').filter(Boolean);
const unlinked = JSON.parse(process.env.UNLINKED || '[]');
/** @type {'success' | 'failure' | 'error' | 'pending'} */
let state;
let description;
if (allSigned) {
state = 'success';
description = 'All contributors have signed the CLA';
} else if (errored.length > 0 && unsigned.length === 0 && unlinked.length === 0) {
state = 'error';
description = `Could not verify: ${errored.join(', ')}`;
} else {
state = 'failure';
const parts = [];
if (unsigned.length > 0) parts.push(`unsigned: ${unsigned.join(', ')}`);
if (errored.length > 0) parts.push(`errored: ${errored.join(', ')}`);
if (unlinked.length > 0) parts.push(`${unlinked.length} unlinked commit(s)`);
description = parts.join(' | ');
}
// GitHub commit status description is capped at 140 chars.
if (description.length > 140) {
description = description.slice(0, 137) + '…';
}
const prNumber = process.env.PR_NUMBER;
const target_url = prNumber
? `${context.payload.repository?.html_url}/pull/${prNumber}`
: process.env.CLA_SIGN_URL;
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: /** @type {string} */ (process.env.HEAD_SHA),
state,
context: /** @type {string} */ (process.env.STATUS_CONTEXT),
description,
target_url,
});
}

76
.github/scripts/cla/resolve-context.mjs vendored Normal file
View File

@ -0,0 +1,76 @@
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
//
// Reads the triggering event (pull_request_target, issue_comment, or
// merge_group) and emits the head/base SHA and PR number that the rest of
// the workflow needs. For /cla-check comments, also leaves an "eyes"
// reaction so the commenter sees we picked it up.
/**
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
* @typedef { import("@actions/github/lib/context").Context } Context
* @typedef { typeof import("@actions/core") } Core
*/
/**
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
*/
export default async function resolveClaContext({ github, context, core }) {
const { owner, repo } = context.repo;
const event = context.eventName;
let prNumber = '';
let headSha = '';
let baseSha = '';
let isMergeGroup = false;
if (event === 'pull_request_target' && context.payload.pull_request) {
const pr = context.payload.pull_request;
prNumber = String(pr.number);
headSha = pr.head.sha;
baseSha = pr.base.sha;
} else if (event === 'issue_comment' && context.payload.issue) {
prNumber = String(context.payload.issue.number);
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: Number(prNumber),
});
headSha = pr.head.sha;
baseSha = pr.base.sha;
// Acknowledge the command so the commenter sees we received it.
try {
await github.rest.reactions.createForIssueComment({
owner,
repo,
comment_id: context.payload.comment?.id || -1,
content: 'eyes',
});
} catch (e) {
core.info(`Could not react to comment: ${e instanceof Error ? e.message : String(e)}`);
}
} else if (event === 'merge_group') {
isMergeGroup = true;
headSha = context.payload.merge_group.head_sha;
baseSha = context.payload.merge_group.base_sha;
} else if (event === 'workflow_dispatch') {
const input = context.payload.inputs?.pr_number;
if (!input) {
core.setFailed('workflow_dispatch requires the pr_number input');
return;
}
prNumber = String(input);
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: Number(prNumber),
});
headSha = pr.head.sha;
baseSha = pr.base.sha;
}
core.setOutput('pr_number', prNumber);
core.setOutput('head_sha', headSha);
core.setOutput('base_sha', baseSha);
core.setOutput('is_merge_group', String(isMergeGroup));
}

View File

@ -0,0 +1,104 @@
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
//
// Maintains a single CLA comment per PR, keyed by an HTML marker so the
// same comment is edited in place across re-runs instead of spammed.
// A clean PR that has never been flagged gets no comment at all — only
// PRs that needed a nudge get the eventual "thanks" follow-up.
/**
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
* @typedef { import("@actions/github/lib/context").Context } Context
* @typedef { typeof import("@actions/core") } Core
*/
/**
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
*/
export default async function updatePRComment({ github, context }) {
const { owner, repo } = context.repo;
const issue_number = Number(process.env.PR_NUMBER);
const allSigned = process.env.ALL_SIGNED === 'true';
const unsigned = (process.env.UNSIGNED ?? '').split(',').filter(Boolean);
const errored = (process.env.ERRORED ?? '').split(',').filter(Boolean);
const unlinked = JSON.parse(process.env.UNLINKED || '[]');
const MARKER = /** @type {string} */ (process.env.COMMENT_MARKER);
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
});
// Only adopt the comment as ours if it's bot-authored — otherwise a user
// who copies our marker into their own comment would either hijack the
// thread or make updateComment 403 with insufficient permissions.
const existing = comments.find(
(c) => c.body && c.body.includes(MARKER) && c.user && c.user.type === 'Bot',
);
let body;
if (allSigned) {
// Only leave a "thanks" trail if we already nudged once. Avoids
// pinging every clean PR with a CLA comment.
if (!existing) {
return;
}
body = [
MARKER,
'✅ **CLA Check passed.** All contributors on this PR have signed the n8n CLA — thank you!',
].join('\n');
} else {
const lines = [MARKER, '## CLA signatures required', ''];
lines.push(`Thank you for your submission! We really appreciate it.
Like many open source projects, we ask that you sign our [Contributor License Agreement](${process.env.CLA_SIGN_URL}) before we can accept your contribution.`);
lines.push('');
if (unsigned.length > 0) {
lines.push('**Contributors who still need to sign:**');
for (const u of unsigned) {
lines.push(`- @${u}`);
}
lines.push('');
}
if (errored.length > 0) {
lines.push('**Could not verify (will retry on next push):**');
for (const u of errored) {
lines.push(`- @${u}`);
}
lines.push('');
}
if (unlinked.length > 0) {
lines.push('**Commits authored by an email not linked to a GitHub account:**');
for (const c of unlinked) {
lines.push(`- \`${c.sha.slice(0, 7)}\`${c.name} <${c.email}>`);
}
lines.push('');
lines.push(
'Add the email to your GitHub account ' +
'([instructions](https://docs.github.com/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account)) ' +
'or amend the commits to use a linked email, then push again.',
);
lines.push('');
}
lines.push('Once signed, comment `/cla-check` on this PR to re-run verification.');
body = lines.join('\n');
}
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
}

View File

@ -32,6 +32,13 @@ let prompt;
if (useRaw) {
prompt = task;
} else if (task.startsWith('/')) {
// Task is a skill invocation (e.g. "/n8n:linear-issue CAT-2820").
// Wrap it so the model invokes the Skill tool instead of implementing code.
prompt = `# Skill Invocation
Invoke the following skill using the Skill tool and follow its instructions.
${task}`;
} else {
// List available templates so Claude knows what exists (reads them if needed)
const templateDir = '.github/claude-templates';

View File

@ -11,7 +11,8 @@
"glob": "13.0.6",
"minimatch": "10.2.4",
"semver": "7.7.4",
"tempfile": "6.0.1"
"tempfile": "6.0.1",
"yaml": "^2.8.3"
},
"devDependencies": {
"conventional-changelog-angular": "8.3.0"

View File

@ -32,6 +32,9 @@ importers:
tempfile:
specifier: 6.0.1
version: 6.0.1
yaml:
specifier: ^2.8.3
version: 2.8.3
devDependencies:
conventional-changelog-angular:
specifier: 8.3.0
@ -292,6 +295,11 @@ packages:
wordwrap@1.0.0:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
yaml@2.8.3:
resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==}
engines: {node: '>= 14.6'}
hasBin: true
snapshots:
'@actions/github@9.0.0':
@ -540,3 +548,5 @@ snapshots:
walk-up-path@4.0.0: {}
wordwrap@1.0.0: {}
yaml@2.8.3: {}

25
.github/scripts/pnpm-utils.mjs vendored Normal file
View File

@ -0,0 +1,25 @@
import child_process from 'child_process';
import { promisify } from 'node:util';
const exec = promisify(child_process.exec);
/**
* @typedef PnpmPackage
* @property { string } name
* @property { string } version
* @property { string } path
* @property { boolean } private
* */
/**
* @returns { Promise<PnpmPackage[]> }
* */
export async function getMonorepoProjects() {
return JSON.parse(
(
await exec(
`pnpm ls -r --only-projects --json | jq -r '[.[] | { name: .name, version: .version, path: .path, private: .private}]'`,
)
).stdout,
);
}

View File

@ -40,6 +40,8 @@ export const EXCLUDE_PATTERNS = [
'packages/testing/**',
// Lock file (can produce massive diffs on dependency changes)
'pnpm-lock.yaml',
'**/*.md',
'**/*.mdx'
];
const BOT_MARKER = '<!-- pr-size-check -->';

View File

@ -203,4 +203,13 @@ describe('countFilteredAdditions', () => {
];
assert.equal(countFilteredAdditions(files, EXCLUDE_PATTERNS), 50);
});
it('applies EXCLUDE_PATTERNS to markdown files', () => {
const files = [
{ filename: 'packages/cli/src/service.ts', additions: 50 },
{ filename: 'packages/cli/AGENTS.md', additions: 100 },
{ filename: 'packages/frontend/STORIES.mdx', additions: 100 },
];
assert.equal(countFilteredAdditions(files, EXCLUDE_PATTERNS), 50);
});
});

View File

@ -2,16 +2,18 @@
/**
* Retry a shell command with configurable attempts and delay.
*
* Usage: node retry.mjs [--attempts N] [--delay N] '<command>'
* Usage (safe): node retry.mjs [--attempts N] [--delay N] -- <cmd> [args...]
* Usage (legacy): node retry.mjs [--attempts N] [--delay N] '<shell command>'
*
* Options:
* --attempts N Maximum number of attempts (default: 4)
* --delay N Seconds to wait between retries (default: 15)
*
* The command is executed via shell, so pipes and env-var expansion work.
* The -- form passes args directly to the process (no shell, safe for untrusted input).
* The legacy form executes via shell, so pipes and env-var expansion work but injection is possible.
* Exits 0 on first success, 1 if all attempts fail.
*/
import { execSync } from 'node:child_process';
import { execSync, spawnSync } from 'node:child_process';
const args = process.argv.slice(2);
@ -29,23 +31,40 @@ function getFlag(name, defaultValue) {
const attempts = getFlag('attempts', 4);
const delay = getFlag('delay', 15);
// Command is the last positional arg (skip flags and their values)
const command = args
.filter((a, i) => {
if (a.startsWith('--')) return false;
if (i > 0 && args[i - 1].startsWith('--')) return false;
return true;
})
.pop();
// Preferred form: -- cmd arg1 arg2 ... (no shell, safe for untrusted input)
// Legacy form: '<shell command string>' (uses shell; kept for backwards compat)
const separatorIndex = args.indexOf('--');
let command;
let commandArgs = [];
const isSafeRetry = separatorIndex !== -1;
if (isSafeRetry) {
[command, ...commandArgs] = args.slice(separatorIndex + 1);
} else {
command = args
.filter((a, i) => {
if (a.startsWith('--')) return false;
if (i > 0 && args[i - 1].startsWith('--')) return false;
return true;
})
.pop();
}
if (!command) {
console.error("Usage: node retry.mjs [--attempts N] [--delay N] '<command>'");
console.error('Usage: node retry.mjs [--attempts N] [--delay N] -- <cmd> [args...]');
process.exit(1);
}
for (let i = 1; i <= attempts; i++) {
try {
execSync(command, { shell: true, stdio: 'inherit' });
if (isSafeRetry) {
const result = spawnSync(command, commandArgs, { stdio: 'inherit' });
if (result.status !== 0) throw new Error(`Exit code ${result.status}`);
} else {
execSync(command, { shell: true, stdio: 'inherit' });
}
process.exit(0);
} catch {
if (i < attempts) {

View File

@ -0,0 +1,72 @@
import { getMonorepoProjects } from './pnpm-utils.mjs';
const NPM_REGISTRY = 'https://registry.npmjs.org';
/**
* @param {string} name
* @param {string} version
* @param {string} tag
* @param {string} token
*/
async function setDistTag(name, version, tag, token) {
// Scoped package names need both @ and / encoded (e.g. @n8n/foo → %40n8n%2ffoo)
const encodedName = encodeURIComponent(name);
const url = `${NPM_REGISTRY}/-/package/${encodedName}/dist-tags/${tag}`;
return fetch(url, {
method: 'PUT',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(version),
});
}
async function setLatestForMonorepoPackages() {
const token = process.env.NPM_TOKEN;
if (!token) {
throw new Error('NPM_TOKEN environment variable is required');
}
const packages = await getMonorepoProjects();
const publishedPackages = packages //
.filter((pkg) => !pkg.private)
.filter((pkg) => pkg.name.startsWith('@n8n/'))
.filter((pkg) => pkg.version);
const failures = [];
for (const pkg of publishedPackages) {
const versionName = `${pkg.name}@${pkg.version}`;
try {
const res = await setDistTag(pkg.name, pkg.version, 'latest', token);
if (res.ok) {
console.log(`Set ${versionName} as latest`);
} else {
const body = await res.text().catch(() => '');
console.error(`Failed to set ${versionName} as latest: HTTP ${res.status} ${body}`);
failures.push(versionName);
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error(`Failed to set ${versionName} as latest: ${message}`);
failures.push(versionName);
}
}
if (failures.length > 0) {
throw new Error(`Failed to update dist-tags for: ${failures.join(', ')}`);
}
}
// only run when executed directly, not when imported by tests
if (import.meta.url === `file://${process.argv[1]}`) {
setLatestForMonorepoPackages().catch((err) => {
console.error(err);
process.exit(1);
});
}

File diff suppressed because it is too large Load Diff

45
.github/test-metrics/quarantine.json vendored Normal file
View File

@ -0,0 +1,45 @@
{
"updatedAt": "2026-05-11T14:16:56.139Z",
"source": "currents",
"projectId": "LRxcNt",
"quarantined": [
"Canvas Actions > Node hover actions > should execute node",
"Chat user role @capability:proxy > use chat as chat user @auth:chat",
"Code node > Code editor > should execute the placeholder successfully in both modes",
"Data Mapping > maps expressions to updated fields correctly @fixme",
"Data pinning > Advanced pinning scenarios > should be able to reference paired items in node before pinned data",
"Debug mode > should enter debug mode for failed executions",
"HITL for Tools @capability:proxy > should add a HITL tool node and run it",
"Inject previous execution > can map keys from previous execution",
"Instance AI remediation guard @capability:proxy > should preserve a submitted workflow when mocked credential verification needs setup",
"Instance AI sidebar @capability:proxy > should delete thread via action menu",
"Instance AI workflow setup actions @capability:proxy > should apply parameter and credential edits and persist them to the workflow",
"Instance AI workflow setup actions @capability:proxy > should partially apply completed cards when Later is clicked on the last step",
"Loads template setup modal correctly",
"NDV Data Display > Schema View > should not display pagination for schema",
"Settings @capability:proxy > set global credentials for a provider",
"Tools usage @capability:proxy > use web search tool in conversation",
"can configure, connect, and sync secrets from LocalStack",
"can create a connection pointing to LocalStack",
"manage workflow agents @auth:admin",
"maps expressions to updated fields correctly @fixme",
"sharing workflow agent with project chat user",
"should add switch node and test connections",
"should allow re-running workflow after initial execution",
"should be able to reference paired items in node before pinned data",
"should clear required-parameter issue indicator when the field is filled",
"should execute node",
"should filter executions by status and show filter badge",
"should maintain zoom functionality after switching between Editor and Workflow history and Workflow list",
"should not send workflow context if nothing changed",
"should open executions tab",
"should populate logs as manual execution progresses",
"should preserve resource mapper values when navigating between connected nodes via floating nodes",
"should render runItems for sub-nodes and allow switching between them",
"should reset filter and remove badge",
"should retrieve list options when other params throw errors",
"should save template id with the workflow",
"should send proper payload for node rerun",
"use web search tool in conversation"
]
}

184
.github/workflows/ci-cla-check.yml vendored Normal file
View File

@ -0,0 +1,184 @@
name: 'CI: CLA Check'
# In-house replacement for the GitHub App "CLA Bot".
#
# Triggers
# - pull_request_target (opened/synchronize/reopened): re-checks signatures
# whenever a PR is opened or new commits are pushed.
# - issue_comment (`/cla-check` on a PR): manual re-check after a contributor
# signs the CLA, without needing a push.
# - merge_group: re-checks at merge-queue time so a ruleset can hard-block
# unsigned merges even if the PR check went stale.
#
# Output
# - A commit status named "CLA Check" on the head SHA. Add this name to a
# ruleset's required-checks list to gate merges on it.
# - A single, edited-in-place PR comment listing unsigned contributors.
#
# Implementation
# The heavy lifting lives in .github/scripts/cla/*.mjs. Each step below
# loads its corresponding module and invokes its default export.
on:
pull_request_target:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]
merge_group:
workflow_dispatch:
inputs:
pr_number:
description: 'Pull request number to re-verify'
required: true
type: string
permissions:
contents: read
pull-requests: write
issues: write
statuses: write
concurrency:
group: cla-check-${{ github.event.pull_request.number || github.event.issue.number || github.event.merge_group.head_sha || github.event.inputs.pr_number || github.ref }}
cancel-in-progress: true
env:
STATUS_CONTEXT: 'CLA Check'
CLA_API: 'https://cla-bot-prod.users.n8n.cloud/webhook/cla/check'
CLA_SIGN_URL: 'https://cla-bot-prod.users.n8n.cloud/webhook/cla'
COMMENT_MARKER: '<!-- n8n-cla-check -->'
jobs:
cla-check:
name: Verify CLA signatures
# Skip issue_comment unless it's on a PR and the body starts with /cla-check.
if: >-
github.event_name != 'issue_comment' ||
(github.event.issue.pull_request != null &&
startsWith(github.event.comment.body, '/cla-check'))
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.N8N_ASSISTANT_APP_ID }}
private-key: ${{ secrets.N8N_ASSISTANT_PRIVATE_KEY }}
- name: Checkout CLA scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: .github/scripts/cla
sparse-checkout-cone-mode: false
- name: Resolve PR context
id: context
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const mod = await import('${{ github.workspace }}/.github/scripts/cla/resolve-context.mjs');
await mod.default({ github, context, core });
- name: Post pending commit status
if: steps.context.outputs.head_sha != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: process.env.HEAD_SHA,
state: 'pending',
context: process.env.STATUS_CONTEXT,
description: 'Verifying CLA signatures…',
});
- name: Check CLA signatures
id: check
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
BASE_SHA: ${{ steps.context.outputs.base_sha }}
IS_MERGE_GROUP: ${{ steps.context.outputs.is_merge_group }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const mod = await import('${{ github.workspace }}/.github/scripts/cla/check-signatures.mjs');
await mod.default({ github, context, core });
- name: Post final commit status
if: always() && steps.context.outputs.head_sha != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
UNSIGNED: ${{ steps.check.outputs.unsigned }}
ERRORED: ${{ steps.check.outputs.errored }}
UNLINKED: ${{ steps.check.outputs.unlinked }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const mod = await import('${{ github.workspace }}/.github/scripts/cla/post-final-status.mjs');
await mod.default({ github, context, core });
- name: Update PR comment
# Don't comment from merge_group (no PR context) or when the check
# failed to produce a result.
if: >-
always() &&
steps.context.outputs.pr_number != '' &&
steps.check.outputs.all_signed != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
UNSIGNED: ${{ steps.check.outputs.unsigned }}
ERRORED: ${{ steps.check.outputs.errored }}
UNLINKED: ${{ steps.check.outputs.unlinked }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const mod = await import('${{ github.workspace }}/.github/scripts/cla/update-pr-comment.mjs');
await mod.default({ github, context, core });
- name: Manage cla-signed label
# Skip on merge_group (no PR) and when the check produced no result.
if: >-
always() &&
steps.context.outputs.pr_number != '' &&
steps.check.outputs.all_signed != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const mod = await import('${{ github.workspace }}/.github/scripts/cla/manage-label.mjs');
await mod.default({ github, context, core });
- name: React to /cla-check comment
if: always() && github.event_name == 'issue_comment' && steps.check.outputs.all_signed != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
try {
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: process.env.ALL_SIGNED === 'true' ? '+1' : '-1',
});
} catch (e) {
core.info(`Could not react to comment: ${e.message}`);
}

View File

@ -0,0 +1,23 @@
# .github/workflows/ci-codeowners-validation.yml
name: "CI: Validate CODEOWNERS"
# Only run when CODEOWNERS or packages change
on:
pull_request:
paths:
- ".github/CODEOWNERS"
- "packages/**"
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: mszostok/codeowners-validator@7f3f5e28c6d7b8dfae5731e54ce2272ca384592f #v0.7.4
with:
# Start with safe checks only. Add "owners" and
# experimental_checks: "notowned" once the file has settled
# and skip patterns are configured.
checks: "files,duppatterns,syntax"
github_access_token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -1,6 +1,7 @@
name: 'CI: PR Quality Checks'
on:
merge_group:
pull_request:
types:
- opened
@ -46,10 +47,14 @@ jobs:
name: Ownership Acknowledgement
# Checks that the author has acknowledged the ownership of their code
# by checking the checkbox in the PR summary.
# Skipped for bot-authored PRs (Dependabot, Renovate, github-actions, Aikido, etc.).
# The required aggregator `required-pr-quality-checks` treats skipped as success.
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
!contains(github.event.pull_request.labels.*.name, 'automation:backport') &&
!contains(github.event.pull_request.title, '(backport to')
!contains(github.event.pull_request.title, '(backport to') &&
github.event.pull_request.user.type != 'Bot'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
@ -73,11 +78,15 @@ jobs:
check-pr-size:
name: PR Size Limit
# Checks that the PR size doesn't exceed the limit (currently 1000 lines)
# Allows for override via '/size-limit-override' comment
# Allows for override via '/size-limit-override' comment.
# Skipped for bot-authored PRs — dep bumps from Dependabot/Renovate/Aikido
# routinely exceed the size limit and shouldn't be gated on it.
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
!contains(github.event.pull_request.labels.*.name, 'automation:backport') &&
!contains(github.event.pull_request.title, '(backport to')
!contains(github.event.pull_request.title, '(backport to') &&
github.event.pull_request.user.type != 'Bot'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
@ -97,3 +106,76 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: node .github/scripts/quality/check-pr-size.mjs
changes:
name: Detect Changes
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
outputs:
janitor: ${{ fromJSON(steps.filter.outputs.results).janitor == true }}
code-health: ${{ fromJSON(steps.filter.outputs.results)['code-health'] == true }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Detect changed paths
id: filter
uses: ./.github/actions/ci-filter
with:
mode: filter
filters: |
janitor:
packages/testing/playwright/**
packages/testing/janitor/**
code-health:
**/package.json
pnpm-workspace.yaml
.code-health-baseline.json
packages/testing/code-health/**
check-static-analysis:
name: Static Analysis
needs: changes
if: |
github.event_name == 'merge_group' ||
needs.changes.outputs.code-health == 'true' ||
needs.changes.outputs.janitor == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: ./.github/actions/setup-nodejs
with:
build-command: pnpm turbo run build --filter=@n8n/code-health --filter=@n8n/playwright-janitor
- name: Run code-health
if: github.event_name == 'merge_group' || needs.changes.outputs.code-health == 'true'
run: pnpm --filter=@n8n/code-health check
- name: Run janitor
if: ${{ !cancelled() && (github.event_name == 'merge_group' || needs.changes.outputs.janitor == 'true') }}
run: pnpm --filter=n8n-playwright janitor
required-pr-quality-checks:
name: Required PR Quality Checks
needs: [check-ownership-checkbox, check-pr-size, check-static-analysis]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: .github/actions/ci-filter
sparse-checkout-cone-mode: false
- name: Validate required checks
uses: ./.github/actions/ci-filter
with:
mode: validate
job-results: ${{ toJSON(needs) }}

View File

@ -41,7 +41,12 @@ jobs:
chromatic:
name: Chromatic
needs: filter
if: needs.filter.outputs.design_system == 'true'
# Skip on fork PRs — they don't have access to the Chromatic secret.
# This job is intentionally not in `required-review-checks` needs, so it
# is non-blocking and won't gate merging.
if: >-
needs.filter.outputs.design_system == 'true' &&
github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/workflows/test-visual-chromatic.yml
with:
ref: ${{ needs.filter.outputs.commit_sha }}
@ -51,7 +56,7 @@ jobs:
# PRs cannot be merged unless this job passes.
required-review-checks:
name: Required Review Checks
needs: [filter, chromatic]
needs: [filter]
if: always()
runs-on: ubuntu-slim
steps:

View File

@ -22,12 +22,17 @@ jobs:
ci: ${{ fromJSON(steps.ci-filter.outputs.results).ci == true }}
unit: ${{ fromJSON(steps.ci-filter.outputs.results).unit == true }}
e2e: ${{ fromJSON(steps.ci-filter.outputs.results).e2e == true }}
dev_server_smoke: ${{ fromJSON(steps.ci-filter.outputs.results)['dev-server-smoke'] == true }}
workflows: ${{ fromJSON(steps.ci-filter.outputs.results).workflows == true }}
workflow_scripts: ${{ fromJSON(steps.ci-filter.outputs.results)['workflow-scripts'] == true }}
db: ${{ fromJSON(steps.ci-filter.outputs.results).db == true }}
performance: ${{ fromJSON(steps.ci-filter.outputs.results).performance == true }}
e2e_performance: ${{ fromJSON(steps.ci-filter.outputs.results)['e2e-performance'] == true }}
instance_ai_workflow_eval: ${{ fromJSON(steps.ci-filter.outputs.results)['instance-ai-workflow-eval'] == true }}
commit_sha: ${{ steps.commit-sha.outputs.sha }}
merge_base: ${{ steps.ci-filter.outputs.merge-base }}
matrix: ${{ steps.generate-matrix.outputs.matrix }}
skip_tests: ${{ steps.generate-matrix.outputs.skip-tests }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
@ -55,20 +60,38 @@ jobs:
!.github/**
e2e:
.github/workflows/test-e2e-*.yml
.github/scripts/cleanup-ghcr-images.mjs
.github/workflows/prepare-docker-reusable.yml
.github/actions/build-n8n-docker/**
.github/actions/load-n8n-docker/**
packages/testing/playwright/**
packages/testing/containers/**
dev-server-smoke:
packages/frontend/editor-ui/vite.config.mts
pnpm-workspace.yaml
packages/@n8n/*/package.json
packages/testing/playwright/tests/dev-server-smoke/**
packages/testing/playwright/playwright.config.ts
packages/testing/playwright/playwright-projects.ts
packages/testing/playwright/package.json
.github/workflows/test-dev-server-smoke-reusable.yml
workflows: .github/**
workflow-scripts: .github/scripts/**
performance:
packages/testing/performance/**
packages/workflow/src/**
packages/@n8n/expression-runtime/src/**
.github/workflows/test-bench-reusable.yml
e2e-performance:
packages/testing/playwright/tests/performance/**
packages/testing/playwright/utils/performance-helper.ts
packages/testing/containers/**
.github/workflows/test-e2e-performance-reusable.yml
instance-ai-workflow-eval:
packages/@n8n/instance-ai/src/**
packages/@n8n/instance-ai/evaluations/**
packages/cli/src/modules/instance-ai/**
packages/core/src/execution-engine/eval-mock-helpers.ts
.github/workflows/test-evals-instance-ai*.yml
db:
packages/cli/src/databases/**
packages/cli/src/modules/*/database/**
@ -83,13 +106,27 @@ jobs:
.github/workflows/test-db-reusable.yml
- name: Setup and Build
if: fromJSON(steps.ci-filter.outputs.results).ci
if: fromJSON(steps.ci-filter.outputs.results).ci || fromJSON(steps.ci-filter.outputs.results).e2e
uses: ./.github/actions/setup-nodejs
with:
build-command: ${{ fromJSON(steps.ci-filter.outputs.results).ci && 'pnpm build' || 'pnpm turbo run build --filter=@n8n/playwright-janitor' }}
- name: Run format check
if: fromJSON(steps.ci-filter.outputs.results).ci
run: pnpm format:check
- name: Generate shard matrix
id: generate-matrix
if: fromJSON(steps.ci-filter.outputs.results).ci || fromJSON(steps.ci-filter.outputs.results).e2e
env:
CHANGED_FILES: ${{ steps.ci-filter.outputs.changed-files }}
MERGE_BASE: ${{ steps.ci-filter.outputs.merge-base }}
run: |
FILES_CSV=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//')
MATRIX=$(node packages/testing/playwright/scripts/distribute-tests.mjs --matrix 16 --orchestrate --impact "--files=$FILES_CSV" "--base=$MERGE_BASE")
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
echo "skip-tests=$(node -e "process.stdout.write(JSON.parse(process.argv[1])[0]?.skip === true ? 'true' : 'false')" "$MATRIX")" >> "$GITHUB_OUTPUT"
unit-test:
name: Unit tests
if: needs.install-and-build.outputs.unit == 'true'
@ -141,14 +178,73 @@ jobs:
run: |
pnpm -r pack --dry-run
e2e-tests:
name: E2E Tests
# Seeds the SHA-keyed Docker image cache once so that downstream e2e jobs
# (each of which invokes prepare-docker internally) short-circuit to a
# cache hit instead of racing to rebuild.
prepare-docker:
name: Prepare Docker
needs: install-and-build
if: (needs.install-and-build.outputs.ci == 'true' || needs.install-and-build.outputs.e2e == 'true') && github.repository == 'n8n-io/n8n' && github.event_name != 'merge_group'
uses: ./.github/workflows/test-e2e-ci-reusable.yml
if: >-
github.repository == 'n8n-io/n8n' &&
github.event_name != 'merge_group' &&
(needs.install-and-build.outputs.ci == 'true'
|| needs.install-and-build.outputs.e2e == 'true'
|| needs.install-and-build.outputs.e2e_performance == 'true')
uses: ./.github/workflows/prepare-docker-reusable.yml
with:
branch: ${{ needs.install-and-build.outputs.commit_sha }}
playwright-only: ${{ needs.install-and-build.outputs.e2e == 'true' && needs.install-and-build.outputs.unit == 'false' }}
secrets: inherit
# Internal-only 1-spec fail-fast sanity check on sqlite.
sqlite-sanity:
name: 'SQLite: Sanity Check'
needs: [install-and-build, prepare-docker]
if: >-
needs.prepare-docker.result == 'success' &&
(needs.install-and-build.outputs.ci == 'true' || needs.install-and-build.outputs.e2e == 'true') &&
github.repository == 'n8n-io/n8n' &&
github.event_name != 'merge_group' &&
github.event.pull_request.head.repo.fork != true
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ needs.install-and-build.outputs.commit_sha }}
test-mode: docker-artifact
test-command: pnpm --filter=n8n-playwright test:container:sqlite:e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts
workers: '1'
artifact-prefix: sanity
secrets: inherit
# Full e2e run. Internal PRs run multi-main (postgres + redis + caddy + 2 mains + 1 worker).
# Fork PRs run sqlite-only and skip @licensed tests (no enterprise license secrets on forks).
e2e:
name: E2E
needs: [install-and-build, prepare-docker]
if: >-
needs.prepare-docker.result == 'success' &&
(needs.install-and-build.outputs.ci == 'true' || needs.install-and-build.outputs.e2e == 'true') &&
needs.install-and-build.outputs.skip_tests != 'true' &&
github.event_name != 'merge_group'
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ needs.install-and-build.outputs.commit_sha }}
test-mode: docker-artifact
test-command: ${{ github.event.pull_request.head.repo.fork == true && 'pnpm --filter=n8n-playwright test:container:sqlite:e2e --grep-invert=@licensed' || 'pnpm --filter=n8n-playwright test:container:multi-main:e2e' }}
workers: '1'
pre-generated-matrix: ${{ needs.install-and-build.outputs.matrix }}
artifact-prefix: e2e
secrets: inherit
# Boots the editor-ui against the Vite dev server and fails on any console
# or page error during load. Catches regressions in dev-mode module
# resolution (missing Vite alias, broken workspace package interop) that
# the production-bundle e2e job bundles around.
dev-server-smoke:
name: Dev-server boot smoke
needs: install-and-build
if: needs.install-and-build.outputs.dev_server_smoke == 'true' && github.event_name != 'merge_group'
uses: ./.github/workflows/test-dev-server-smoke-reusable.yml
with:
ref: ${{ needs.install-and-build.outputs.commit_sha }}
secrets: inherit
db-tests:
@ -169,11 +265,12 @@ jobs:
e2e-performance:
name: E2E Performance
needs: install-and-build
needs: [install-and-build, prepare-docker]
# Performance is internal-only (license secrets required, not available on forks).
if: >-
(needs.install-and-build.outputs.ci == 'true' || needs.install-and-build.outputs.e2e_performance == 'true') &&
github.event_name == 'pull_request' &&
github.repository == 'n8n-io/n8n'
needs.prepare-docker.result == 'success' &&
needs.install-and-build.outputs.e2e_performance == 'true' &&
github.event.pull_request.head.repo.fork != true
uses: ./.github/workflows/test-e2e-performance-reusable.yml
secrets: inherit
@ -195,6 +292,23 @@ jobs:
ref: ${{ needs.install-and-build.outputs.commit_sha }}
secrets: inherit
# Depends on prepare-docker so the eval workflow can load the SHA-keyed image cache.
# prepare-docker may be skipped (its filter excludes .github/**); the eval falls back to a local build.
instance-ai-workflow-evals:
name: Instance AI Workflow Evals
needs: [install-and-build, prepare-docker]
if: >-
!cancelled() &&
needs.install-and-build.result == 'success' &&
(needs.prepare-docker.result == 'success' || needs.prepare-docker.result == 'skipped') &&
needs.install-and-build.outputs.instance_ai_workflow_eval == 'true' &&
github.repository == 'n8n-io/n8n' &&
(github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork)
uses: ./.github/workflows/test-evals-instance-ai.yml
with:
branch: ${{ needs.install-and-build.outputs.commit_sha }}
secrets: inherit
# This job is required by GitHub branch protection rules.
# PRs cannot be merged unless this job passes.
required-checks:
@ -206,7 +320,9 @@ jobs:
typecheck,
lint,
check-packaging,
e2e-tests,
sqlite-sanity,
e2e,
dev-server-smoke,
db-tests,
performance,
security-checks,

View File

@ -4,6 +4,7 @@ on:
pull_request:
branches:
- master
- 1.x
permissions:
pull-requests: write
@ -46,7 +47,7 @@ jobs:
`${marker}\n` +
`🚫 **Merge blocked**: PRs into \`${base}\` are only allowed from branches named \`bundle/*\`.\n\n` +
`Current source branch: \`${head}\`\n\n` +
`Merge your developments into a bundle branch instead of directly merging to master.`;
`Merge your developments into a bundle branch instead of directly merging to master or 1.x.`;
// Find an existing marker comment (to update instead of spamming)
const { data: comments } = await github.rest.issues.listComments({
@ -79,7 +80,7 @@ jobs:
env:
HEAD_REF: ${{ github.head_ref }}
run: |
echo "::error::You can only merge to master from a bundle/* branch. Got '$HEAD_REF'."
echo "::error::You can only merge to master and 1.x from a bundle/* branch. Got '$HEAD_REF'."
exit 1
- name: Allowed

View File

@ -58,14 +58,18 @@ jobs:
- name: Determine build context
id: context
env:
N8N_VERSION: ${{ inputs.n8n_version }}
RELEASE_TYPE: ${{ inputs.release_type }}
PUSH_ENABLED: ${{ inputs.push_enabled }}
run: |
node .github/scripts/docker/docker-config.mjs \
--event "${{ github.event_name }}" \
--pr "${{ github.event.pull_request.number }}" \
--branch "${{ github.ref_name }}" \
--version "${{ inputs.n8n_version }}" \
--release-type "${{ inputs.release_type }}" \
--push-enabled "${{ inputs.push_enabled }}"
--version "$N8N_VERSION" \
--release-type "$RELEASE_TYPE" \
--push-enabled "$PUSH_ENABLED"
build-and-push-docker:
name: Build App, then Build and Push Docker Image (${{ matrix.platform }})

View File

@ -0,0 +1,49 @@
name: 'Prepare n8n Docker (reusable)'
# Reusable workflow that ensures the n8n + runners CI test images for the
# current commit SHA are present in the GHA cache. Cache-aware: if another
# job in the same run already populated `n8n-docker-image-<sha>`, this
# becomes a no-op.
#
# Downstream jobs restore the same SHA-keyed cache via load-n8n-docker.
on:
workflow_call:
inputs:
build-variant:
description: 'standard or coverage'
required: false
default: 'standard'
type: string
runner:
description: 'Runner for the build.'
required: false
default: 'blacksmith-4vcpu-ubuntu-2204'
type: string
branch:
description: 'Git ref to check out.'
required: false
default: ''
type: string
jobs:
prepare:
name: 'Build & publish image'
runs-on: ${{ inputs.runner }}
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1
- name: Build and publish image
uses: ./.github/actions/build-n8n-docker
with:
build-variant: ${{ inputs.build-variant }}
env:
QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }}
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }}

View File

@ -0,0 +1,43 @@
name: 'Release: Build Daytona snapshot'
on:
workflow_call:
inputs:
n8n_version:
description: 'n8n version to build the Daytona snapshot for'
required: true
type: string
secrets:
DAYTONA_API_KEY:
required: true
DAYTONA_API_URL:
required: false
workflow_dispatch:
inputs:
n8n_version:
description: 'n8n version to build the Daytona snapshot for (e.g. 1.123.0)'
required: true
type: string
permissions:
contents: read
jobs:
build-snapshot:
name: Build versioned Daytona snapshot
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js and build
uses: ./.github/actions/setup-nodejs
- name: Build versioned Daytona snapshot
env:
N8N_VERSION: ${{ inputs.n8n_version }}
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
DAYTONA_API_URL: ${{ secrets.DAYTONA_API_URL }}
run: node packages/@n8n/instance-ai/scripts/build-snapshot.cjs --version "$N8N_VERSION"

View File

@ -3,7 +3,7 @@ name: 'Release: Create Minor Release PR'
on:
workflow_dispatch:
schedule:
- cron: 0 13 * * 1 # 2pm CET (UTC+1), Monday
- cron: 0 8 * * 2 # 9am CET (UTC+1), Tuesday
jobs:
create-release-pr:

View File

@ -47,7 +47,7 @@ jobs:
echo "Package '$PACKAGE_NAME' does not exist on NPM yet. Proceeding with publish."
- name: Configure NPM token
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_INITIAL_PUBLISH_TOKEN }}" > ~/.npmrc
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_DIST_TAG_AND_INITIAL_PUBLISH_TOKEN }}" > ~/.npmrc
- name: Publish package
working-directory: ${{ github.event.inputs.package-path }}

View File

@ -66,6 +66,14 @@ jobs:
uses: ./.github/workflows/util-ensure-release-candidate-branches.yml
secrets: inherit
ensure-correct-latest-version-on-npm:
name: Ensure correct latest version on npm
if: |
inputs.bump == 'minor' ||
inputs.track == 'stable'
uses: ./.github/workflows/release-set-stable-npm-packages-to-latest.yml
secrets: inherit
populate-cloud-with-releases:
name: 'Populate cloud database with releases'
uses: ./.github/workflows/release-populate-cloud-with-releases.yml

View File

@ -76,15 +76,13 @@ jobs:
cp README.md packages/cli/README.md
sed -i "s/default: 'dev'/default: '${{ needs.determine-version-info.outputs.release_type }}'/g" packages/cli/dist/config/schema.js
- name: Publish n8n to NPM with rc tag
env:
PUBLISH_BRANCH: ${{ github.event.pull_request.base.ref }}
run: pnpm --filter n8n publish --publish-branch "$PUBLISH_BRANCH" --access public --tag rc --no-git-checks
# Publishing via `pnpm publish -r` is idempotent, as it checks if the package exists
# and only publishes if it doesn't. This is why we do the sub-packages before the main n8n package.
# So if anything goes wrong, we can easily re-try the run instead of abandoning the release.
- name: Publish other packages to NPM
env:
PUBLISH_BRANCH: ${{ github.event.pull_request.base.ref }}
PUBLISH_TAG: ${{ needs.determine-version-info.outputs.track == 'stable' && 'latest' || needs.determine-version-info.outputs.track }}
PUBLISH_TAG: ${{ needs.determine-version-info.outputs.track }}
run: |
# Prefix version-like track names (e.g. "1", "v1") to avoid npm rejecting them as semver ranges
if [[ "$PUBLISH_TAG" =~ ^v?[0-9] ]]; then
@ -92,6 +90,12 @@ jobs:
fi
pnpm publish -r --filter '!n8n' --publish-branch "$PUBLISH_BRANCH" --access public --tag "$PUBLISH_TAG" --no-git-checks
# If we don't use the --tag rc, all releases will default to "latest".
- name: Publish n8n to NPM with rc tag
env:
PUBLISH_BRANCH: ${{ github.event.pull_request.base.ref }}
run: pnpm --filter n8n publish --publish-branch "$PUBLISH_BRANCH" --access public --tag rc --no-git-checks
- name: Cleanup rc tag
run: npm dist-tag rm n8n rc
continue-on-error: true
@ -105,6 +109,15 @@ jobs:
release_type: ${{ needs.determine-version-info.outputs.release_type }}
secrets: inherit
build-daytona-snapshot:
name: Build Daytona snapshot
needs: [determine-version-info, publish-to-npm]
if: github.event.pull_request.merged == true
uses: ./.github/workflows/release-build-daytona-snapshot.yml
with:
n8n_version: ${{ needs.determine-version-info.outputs.version }}
secrets: inherit
create-github-release:
name: Create GitHub Release
needs: [determine-version-info, publish-to-npm, publish-to-docker-hub]
@ -183,11 +196,13 @@ jobs:
create-github-release,
move-track-tag,
promote-stable-tag,
build-daytona-snapshot,
]
if: |
always() &&
needs.publish-to-npm.result == 'success' &&
needs.create-github-release.result == 'success' &&
needs.build-daytona-snapshot.result == 'success' &&
(needs.move-track-tag.result == 'success' || needs.move-track-tag.result == 'skipped') &&
(needs.promote-stable-tag.result == 'success' || needs.promote-stable-tag.result == 'skipped')
uses: ./.github/workflows/release-publish-post-release.yml

View File

@ -3,7 +3,7 @@ name: 'Release: Schedule Patch Release PRs'
on:
workflow_dispatch:
schedule:
- cron: '0 8 * * 2-5' # 9am CET (UTC+1), TuesdayFriday
- cron: '0 8 * * 3-5,1' # 9am CET (UTC+1), Wednesday - Friday and Monday. (Minor release on tuesday)
jobs:
create-patch-prs:

View File

@ -0,0 +1,32 @@
name: 'Release: Set stable npm packages to latest'
on:
workflow_call:
workflow_dispatch:
permissions:
contents: write
jobs:
promote-github-releases:
name: Promote current stable releases as latest
runs-on: ubuntu-slim
environment: release
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: refs/tags/stable
fetch-depth: 1
- name: Setup NodeJS
uses: ./.github/actions/setup-nodejs
with:
build-command: ''
install-command: pnpm install --frozen-lockfile --dir ./.github/scripts --ignore-workspace
- name: Set npm packages to latest
run: node ./.github/scripts/set-latest-for-monorepo-packages.mjs
env:
NPM_TOKEN: ${{ secrets.NPM_DIST_TAG_AND_INITIAL_PUBLISH_TOKEN }}

View File

@ -56,7 +56,7 @@ jobs:
output-file: sbom-source.cdx.json
- name: Attest SBOM for source release
uses: actions/attest-sbom@07e74fc4e78d1aad915e867f9a094073a9f71527 # v4.0.0
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-path: './package.json'
sbom-path: 'sbom-source.cdx.json'
@ -64,9 +64,10 @@ jobs:
- name: Attach SBOM and VEX files to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG_REF: ${{ inputs.release_tag_ref }}
run: |
# Upload SBOM and VEX files to the existing release
gh release upload "${{ inputs.release_tag_ref }}" \
gh release upload "$RELEASE_TAG_REF" \
sbom-source.cdx.json \
security/vex.openvex.json \
--clobber

View File

@ -40,6 +40,9 @@ jobs:
token: ${{ steps.app-token.outputs.token }}
- name: Sync master from public
env:
EVENT_NAME: ${{ github.event_name }}
FORCE: ${{ inputs.force }}
run: |
git fetch https://github.com/n8n-io/n8n.git master:public-master
@ -47,10 +50,10 @@ jobs:
AHEAD_COUNT=$(git rev-list public-master..HEAD --pretty=oneline --grep="chore: Bundle" --invert-grep --count)
if [ "$AHEAD_COUNT" -gt 0 ]; then
if [ "${{ github.event_name }}" = "schedule" ]; then
if [ "$EVENT_NAME" = "schedule" ]; then
echo "Private is $AHEAD_COUNT commit(s) ahead of public, skipping scheduled sync"
exit 0
elif [ "${{ inputs.force }}" != "true" ]; then
elif [ "$FORCE" != "true" ]; then
echo "Private is $AHEAD_COUNT commit(s) ahead of public, skipping (force not enabled)"
exit 0
else
@ -62,6 +65,9 @@ jobs:
git push origin master --force-with-lease
- name: Sync 1.x from public
env:
EVENT_NAME: ${{ github.event_name }}
FORCE: ${{ inputs.force }}
run: |
git fetch https://github.com/n8n-io/n8n.git 1.x:public-1.x
git checkout 1.x
@ -70,10 +76,10 @@ jobs:
AHEAD_COUNT=$(git rev-list public-1.x..HEAD --pretty=oneline --grep="chore: Bundle" --invert-grep --count)
if [ "$AHEAD_COUNT" -gt 0 ]; then
if [ "${{ github.event_name }}" = "schedule" ]; then
if [ "$EVENT_NAME" = "schedule" ]; then
echo "Private 1.x is $AHEAD_COUNT commit(s) ahead of public, skipping scheduled sync"
exit 0
elif [ "${{ inputs.force }}" != "true" ]; then
elif [ "$FORCE" != "true" ]; then
echo "Private 1.x is $AHEAD_COUNT commit(s) ahead of public, skipping (force not enabled)"
exit 0
else

View File

@ -40,7 +40,9 @@ jobs:
sparse-checkout-cone-mode: false
- name: Pull Docker image with retry
run: node .github/scripts/retry.mjs --attempts 4 --delay 15 'docker pull "${{ inputs.image_ref }}"'
env:
IMAGE_REF: ${{ inputs.image_ref }}
run: node .github/scripts/retry.mjs --attempts 4 --delay 15 -- docker pull "$IMAGE_REF"
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@e368e328979b113139d6f9068e03accaed98a518 # v0.34.1
@ -90,11 +92,13 @@ jobs:
- name: Generate GitHub Job Summary
if: always()
env:
IMAGE_REF: ${{ inputs.image_ref }}
run: |
{
echo "# 🛡️ Trivy Security Scan Results"
echo ""
echo "**Image:** \`${{ inputs.image_ref }}\`"
echo "**Image:** \`$IMAGE_REF\`"
echo "**Scan Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
@ -125,7 +129,7 @@ jobs:
{
# Generate detailed vulnerability table
jq -r --arg image_ref "${{ inputs.image_ref }}" '
jq -r --arg image_ref "$IMAGE_REF" '
# Collect all vulnerabilities
[.Results[] | select(.Vulnerabilities != null) | .Vulnerabilities[]] |
# Group by CVE ID to avoid duplicates
@ -165,8 +169,10 @@ jobs:
- name: Generate Slack Blocks JSON
if: steps.process_results.outputs.vulnerabilities_found == 'true'
id: generate_blocks
env:
IMAGE_REF: ${{ inputs.image_ref }}
run: |
BLOCKS_JSON=$(jq -c --arg image_ref "${{ inputs.image_ref }}" \
BLOCKS_JSON=$(jq -c --arg image_ref "$IMAGE_REF" \
--arg repo_url "${{ github.server_url }}/${{ github.repository }}" \
--arg repo_name "${{ github.repository }}" \
--arg run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \

View File

@ -0,0 +1,49 @@
name: 'Test: Dev-server boot smoke'
on:
workflow_call:
inputs:
ref:
description: 'Git ref to test'
required: true
type: string
env:
NODE_OPTIONS: '--max-old-space-size=6144'
PLAYWRIGHT_BROWSERS_PATH: packages/testing/playwright/.playwright-browsers
jobs:
smoke:
name: Dev-server smoke
runs-on: ${{ vars.RUNNER_PROVIDER == 'github' && 'ubuntu-latest' || 'blacksmith-4vcpu-ubuntu-2204' }}
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
ref: ${{ inputs.ref }}
- name: Setup and Build
uses: ./.github/actions/setup-nodejs
- name: Install Browsers
run: pnpm turbo run install-browsers --filter=n8n-playwright
- name: Run dev-server smoke spec
# Run from repo root so PLAYWRIGHT_BROWSERS_PATH (relative) resolves
# correctly. cd-ing into the playwright package double-nests it.
run: pnpm --filter=n8n-playwright test:dev-server-smoke --reporter=list
- name: Upload Failure Artifacts
if: ${{ failure() }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: dev-server-smoke-report
path: |
packages/testing/playwright/test-results/
packages/testing/playwright/playwright-report/
retention-days: 7

View File

@ -1,176 +0,0 @@
name: 'Test: E2E CI'
on:
workflow_call:
inputs:
branch:
description: 'GitHub branch/ref to test'
required: false
type: string
default: ''
playwright-only:
description: 'Only Playwright files changed — run impacted tests only'
required: false
type: boolean
default: false
n8n-env:
description: 'JSON string of n8n env vars to inject into test containers, e.g. {"N8N_EXPRESSION_ENGINE":"vm"}'
required: false
type: string
default: ''
workflow_dispatch:
inputs:
branch:
description: 'GitHub branch/ref to test'
required: false
type: string
default: ''
playwright-only:
description: 'Only Playwright files changed — run impacted tests only'
required: false
type: boolean
default: false
n8n-env:
description: 'JSON string of n8n env vars to inject into test containers (e.g. {"N8N_EXPRESSION_ENGINE":"vm"})'
required: false
type: string
default: ''
env:
DOCKER_IMAGE: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }}
jobs:
prepare:
name: 'Prepare E2E'
if: ${{ !github.event.pull_request.head.repo.fork }}
runs-on: blacksmith-4vcpu-ubuntu-2204
permissions:
packages: write
contents: read
outputs:
matrix: ${{ steps.generate-matrix.outputs.matrix }}
skip-tests: ${{ steps.generate-matrix.outputs.skip-tests }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1
- name: Login to GHCR
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push to GHCR
uses: ./.github/actions/setup-nodejs
with:
build-command: 'pnpm build:docker'
enable-docker-cache: true
env:
INCLUDE_TEST_CONTROLLER: 'true'
IMAGE_BASE_NAME: ghcr.io/${{ github.repository }}
IMAGE_TAG: ci-${{ github.run_id }}
RUNNERS_IMAGE_BASE_NAME: ghcr.io/${{ github.repository_owner }}/runners
QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }}
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }}
- name: Get changed files for impact analysis
if: ${{ inputs.playwright-only }}
id: changed-files
run: |
git fetch --depth=1 origin ${{ github.event.pull_request.base.ref || 'master' }}
echo "list=$(git diff --name-only FETCH_HEAD HEAD | tr '\n' ',' | sed 's/,$//')" >> "$GITHUB_OUTPUT"
- name: Generate shard matrix
id: generate-matrix
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.list }}
run: |
ARGS=(--matrix 16 --orchestrate)
if [[ "${{ inputs.playwright-only }}" == "true" ]]; then
ARGS+=(--impact "--files=$CHANGED_FILES" "--base=FETCH_HEAD")
fi
MATRIX=$(node packages/testing/playwright/scripts/distribute-tests.mjs "${ARGS[@]}")
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
echo "skip-tests=$(node -e "process.stdout.write(JSON.parse(process.argv[1])[0]?.skip === true ? 'true' : 'false')" "$MATRIX")" >> "$GITHUB_OUTPUT"
sqlite-sanity:
needs: [prepare]
name: 'SQLite: Sanity Check'
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ inputs.branch }}
test-mode: docker-pull
docker-image: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }}
test-command: pnpm --filter=n8n-playwright test:container:sqlite:e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts
shards: 1
runner: blacksmith-2vcpu-ubuntu-2204
workers: '1'
pre-generated-matrix: '[{"shard":1,"images":""}]'
n8n-env: ${{ inputs.n8n-env }}
# Multi-main: postgres + redis + caddy + 2 mains + 1 worker
# Only runs for internal PRs (not community/fork PRs)
# Pulls pre-built Docker image from GHCR
multi-main-e2e:
needs: [prepare]
name: 'Multi-Main: E2E'
if: ${{ !github.event.pull_request.head.repo.fork && needs.prepare.outputs.skip-tests != 'true' }}
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ inputs.branch }}
test-mode: docker-pull
docker-image: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }}
test-command: pnpm --filter=n8n-playwright test:container:multi-main:e2e
shards: 16
runner: blacksmith-2vcpu-ubuntu-2204
workers: '1'
use-custom-orchestration: true
pre-generated-matrix: ${{ needs.prepare.outputs.matrix }}
n8n-env: ${{ inputs.n8n-env }}
secrets: inherit
# Community PR tests: Local mode with SQLite (no container building, no secrets required)
# Runs on GitHub-hosted runners without Currents reporting
community-e2e:
name: 'Community: E2E'
if: ${{ github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ inputs.branch }}
test-mode: local
test-command: pnpm --filter=n8n-playwright test:local
shards: 7
runner: ubuntu-latest
workers: '1'
upload-failure-artifacts: true
# Cleanup ephemeral Docker image from GHCR after tests complete
# Local runner cleanup is handled by each test shard in test-e2e-reusable.yml
cleanup-ghcr:
name: 'Cleanup GHCR Image'
needs: [prepare, multi-main-e2e, sqlite-sanity]
if: ${{ !failure() && !cancelled() && !github.event.pull_request.head.repo.fork }}
runs-on: blacksmith-2vcpu-ubuntu-2204
permissions:
packages: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: .github/scripts
sparse-checkout-cone-mode: false
- name: Delete images from GHCR
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHCR_ORG: ${{ github.repository_owner }}
GHCR_REPO: ${{ github.event.repository.name }}
run: node .github/scripts/cleanup-ghcr-images.mjs --tag ci-${{ github.run_id }}

View File

@ -5,48 +5,58 @@ on:
- cron: '0 2 * * 1' # Every Monday at 2 AM
workflow_dispatch: # Allow manual triggering
env:
NODE_OPTIONS: --max-old-space-size=16384
PLAYWRIGHT_WORKERS: 4
PLAYWRIGHT_BROWSERS_PATH: packages/testing/playwright/.playwright-browsers
jobs:
coverage:
runs-on: blacksmith-8vcpu-ubuntu-2204
name: Coverage Tests
prepare-docker:
name: Prepare Docker (coverage)
uses: ./.github/workflows/prepare-docker-reusable.yml
with:
build-variant: coverage
runner: blacksmith-8vcpu-ubuntu-2204
secrets: inherit
e2e:
name: E2E (coverage)
needs: prepare-docker
uses: ./.github/workflows/test-e2e-reusable.yml
with:
test-mode: docker-artifact
test-command: pnpm --filter=n8n-playwright test:container:coverage
workers: '1'
runner: blacksmith-4vcpu-ubuntu-2204
timeout-minutes: 45
pre-generated-matrix: '[{"shard":1,"images":""},{"shard":2,"images":""},{"shard":3,"images":""},{"shard":4,"images":""}]'
artifact-prefix: coverage
secrets: inherit
aggregate:
name: Aggregate Coverage
needs: e2e
if: always() && needs.e2e.result != 'skipped' && needs.e2e.result != 'cancelled'
runs-on: blacksmith-4vcpu-ubuntu-2204
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Environment
uses: ./.github/actions/setup-nodejs
env:
INCLUDE_TEST_CONTROLLER: 'true'
- name: Build Docker Image with Coverage
run: pnpm build:docker:coverage
env:
INCLUDE_TEST_CONTROLLER: 'true'
- name: Download shard artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
pattern: coverage-shard-*
path: /tmp/shards/
- name: Install Browsers
run: pnpm turbo run install-browsers --filter=n8n-playwright
- name: Run Container Coverage Tests
id: coverage-tests
- name: Collect coverage JSON
shell: bash
run: |
pnpm --filter n8n-playwright test:container:sqlite \
--workers=${{ env.PLAYWRIGHT_WORKERS }}
env:
BUILD_WITH_COVERAGE: 'true'
CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }}
CURRENTS_PROJECT_ID: 'LRxcNt'
QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }}
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }}
mkdir -p packages/testing/playwright/.nyc_output/coverage
found=$(find /tmp/shards -path '*/.nyc_output/coverage/*.json' 2>/dev/null | wc -l)
echo "Found $found coverage JSON files across shards"
find /tmp/shards -path '*/.nyc_output/coverage/*.json' \
-exec cp {} packages/testing/playwright/.nyc_output/coverage/ \;
ls -la packages/testing/playwright/.nyc_output/coverage/ || true
- name: Generate Coverage Report
if: always() && steps.coverage-tests.outcome != 'skipped'
run: pnpm --filter n8n-playwright coverage:report
- name: Upload Coverage Report Artifact
@ -68,7 +78,7 @@ jobs:
fail_ci_if_error: false
- name: Analyse Coverage Gaps
if: always() && steps.coverage-tests.outcome != 'skipped'
if: always()
env:
CODECOV_API_TOKEN: ${{ secrets.CODECOV_API_TOKEN }}
run: |
@ -76,7 +86,7 @@ jobs:
--md --top=15 --out-json=coverage-gaps.json >> "$GITHUB_STEP_SUMMARY"
- name: Upload Coverage Gap Report
if: always() && steps.coverage-tests.outcome != 'skipped'
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: coverage-gap-report

View File

@ -1,38 +0,0 @@
name: 'Test: E2E Docker Pull'
# This workflow is used to run Playwright tests in a Docker container pulled from the registry
on:
workflow_call:
inputs:
shards:
description: 'Shards for parallel execution'
required: false
default: 1
type: number
image:
description: 'Image to use'
required: false
default: 'n8nio/n8n:nightly'
type: string
workflow_dispatch:
inputs:
shards:
description: 'Shards for parallel execution'
required: false
default: 1
type: number
image:
description: 'Image to use'
required: false
default: 'n8nio/n8n:nightly'
type: string
jobs:
build-and-test:
uses: ./.github/workflows/test-e2e-reusable.yml
with:
test-mode: docker-pull
shards: ${{ inputs.shards }}
docker-image: ${{ inputs.image }}
test-command: pnpm --filter=n8n-playwright test:container:standard
secrets: inherit

View File

@ -17,23 +17,26 @@ concurrency:
cancel-in-progress: true
jobs:
prepare-docker:
uses: ./.github/workflows/prepare-docker-reusable.yml
secrets: inherit
benchmark:
name: ${{ matrix.profile }}
needs: [prepare-docker]
name: benchmarking
strategy:
fail-fast: false
matrix:
include:
- profile: benchmark-direct
runner: blacksmith-4vcpu-ubuntu-2204
- profile: benchmark-queue
runner: blacksmith-8vcpu-ubuntu-2204
- profile: benchmark-queue-tuned
runner: blacksmith-8vcpu-ubuntu-2204
- runner: blacksmith-8vcpu-ubuntu-2204
uses: ./.github/workflows/test-e2e-reusable.yml
with:
test-mode: docker-build
test-command: pnpm --filter=n8n-playwright test:all --project='${{ matrix.profile }}:infrastructure' --workers=1
shards: 1
test-mode: docker-artifact
# Runs the full benchmark suite. Each spec brings its own container via
# `test.use({ capability })`, so workers must be 1 (one container at a time).
test-command: 'pnpm --filter=n8n-playwright test:benchmark'
workers: '1'
runner: ${{ matrix.runner }}
timeout-minutes: 60
timeout-minutes: 120
artifact-prefix: benchmark
secrets: inherit

View File

@ -7,11 +7,17 @@ on:
- cron: '0 0 * * *' # Runs daily at midnight
jobs:
# Cache-aware: no-op if an ancestor already populated the SHA-keyed cache.
prepare-docker:
uses: ./.github/workflows/prepare-docker-reusable.yml
secrets: inherit
build-and-test-performance:
needs: [prepare-docker]
uses: ./.github/workflows/test-e2e-reusable.yml
with:
test-mode: docker-build
test-mode: docker-artifact
test-command: pnpm --filter=n8n-playwright test:performance
shards: 1
currents-project-id: 'O9BJaN'
artifact-prefix: performance
secrets: inherit

View File

@ -8,7 +8,7 @@ on:
required: false
type: string
test-mode:
description: 'Test mode: local (pnpm start from local), docker-build, or docker-pull'
description: 'Test mode: local or docker-artifact'
required: false
default: 'local'
type: string
@ -17,16 +17,6 @@ on:
required: false
default: 'pnpm --filter=n8n-playwright test:local'
type: string
shards:
description: 'Number of parallel shards'
required: false
default: 8
type: number
docker-image:
description: 'Docker image to use (for docker-pull mode). The runners image is derived automatically from the n8n image.'
required: false
default: 'n8nio/n8n:nightly'
type: string
workers:
description: 'Number of parallel workers'
required: false
@ -37,80 +27,53 @@ on:
required: false
default: 'blacksmith-2vcpu-ubuntu-2204'
type: string
use-custom-orchestration:
description: 'Use duration-based custom orchestration instead of Playwright sharding'
required: false
default: false
type: boolean
timeout-minutes:
description: 'Job timeout in minutes'
required: false
default: 30
type: number
upload-failure-artifacts:
description: 'Upload test failure artifacts (screenshots, traces, videos). Enable for community PRs without Currents access.'
required: false
default: false
type: boolean
currents-project-id:
description: 'Currents project ID for reporting'
required: false
default: 'LRxcNt'
type: string
pre-generated-matrix:
description: 'Pre-generated shard matrix JSON (skips matrix job if provided)'
description: 'Pre-generated shard matrix JSON. Defaults to 1 shard; multi-shard callers pass their own.'
required: false
default: ''
default: '[{"shard":1,"images":""}]'
type: string
n8n-env:
description: 'JSON string of n8n env vars to inject into test containers, e.g. {"N8N_EXPRESSION_ENGINE":"vm"}'
required: false
default: ''
type: string
artifact-prefix:
description: 'Prefix for uploaded shard artifacts'
required: false
default: 'e2e'
type: string
env:
NODE_OPTIONS: ${{ contains(inputs.runner, '2vcpu') && '--max-old-space-size=6144' || '' }}
PLAYWRIGHT_WORKERS: ${{ inputs.workers != '' && inputs.workers || '2' }}
# Browser cache location - must match install-browsers script
PLAYWRIGHT_BROWSERS_PATH: packages/testing/playwright/.playwright-browsers
TEST_IMAGE_N8N: ${{ inputs.test-mode == 'docker-build' && 'n8nio/n8n:local' || inputs.docker-image }}
# docker-artifact loads the image locally as n8nio/n8n:local; unused in local mode.
TEST_IMAGE_N8N: 'n8nio/n8n:local'
N8N_SKIP_LICENSES: 'true'
CURRENTS_CI_BUILD_ID: ${{ github.repository }}-${{ github.run_id }}-${{ github.run_attempt }}
CURRENTS_PROJECT_ID: ${{ inputs.currents-project-id }}
jobs:
matrix:
if: ${{ inputs.pre-generated-matrix == '' }}
runs-on: ${{ vars.RUNNER_PROVIDER == 'github' && 'ubuntu-latest' || 'blacksmith-2vcpu-ubuntu-2204' }}
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1
- name: Setup Environment
uses: ./.github/actions/setup-nodejs
with:
build-command: ''
- name: Generate shard matrix
id: generate
run: echo "matrix=$(node packages/testing/playwright/scripts/distribute-tests.mjs --matrix ${{ inputs.shards }} ${{ inputs.use-custom-orchestration && '--orchestrate' || '' }})" >> "$GITHUB_OUTPUT"
test:
needs: matrix
if: ${{ !cancelled() }}
runs-on: ${{ vars.RUNNER_PROVIDER == 'github' && 'ubuntu-latest' || inputs.runner }}
timeout-minutes: ${{ inputs.timeout-minutes }}
permissions:
packages: read
contents: read
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(inputs.pre-generated-matrix || needs.matrix.outputs.matrix) }}
include: ${{ fromJSON(inputs.pre-generated-matrix) }}
name: Shard ${{ matrix.shard }}
steps:
@ -122,14 +85,7 @@ jobs:
- name: Setup Environment
uses: ./.github/actions/setup-nodejs
with:
# docker-build: build app + docker image locally
# docker-pull: no build needed, image is pre-built
# local: build app for local server
build-command: ${{ inputs.test-mode == 'docker-build' && 'pnpm build:docker' || 'pnpm build' }}
enable-docker-cache: ${{ inputs.test-mode == 'docker-build' }}
env:
INCLUDE_TEST_CONTROLLER: ${{ inputs.test-mode == 'docker-build' && 'true' || '' }}
QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }}
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }}
@ -137,18 +93,25 @@ jobs:
- name: Install Browsers
run: pnpm turbo run install-browsers --filter=n8n-playwright
- name: Login to GHCR
if: ${{ inputs.test-mode == 'docker-pull' }}
uses: ./.github/actions/docker-registry-login
- name: Load n8n image from cache
if: ${{ inputs.test-mode == 'docker-artifact' }}
uses: ./.github/actions/load-n8n-docker
- name: Pre-pull Test Container Images
if: ${{ !contains(inputs.test-command, 'test:local') }}
run: npx tsx packages/testing/containers/pull-test-images.ts ${{ matrix.images }} || true
- name: Run Tests
# Uses pre-distributed specs if orchestration enabled, otherwise falls back to Playwright sharding
run: ${{ inputs.test-command }} --workers=${{ env.PLAYWRIGHT_WORKERS }} ${{ matrix.specs || format('--shard={0}/{1}', matrix.shard, strategy.job-total) }}
run: |
# shellcheck disable=SC2086
$TEST_COMMAND --workers="$WORKERS" $SHARD_ARGS
env:
# Protect args from template injections
TEST_COMMAND: ${{ inputs.test-command }}
# Uses pre-distributed specs if orchestration enabled, otherwise falls back to Playwright sharding
WORKERS: ${{ env.PLAYWRIGHT_WORKERS }}
SHARD_ARGS: ${{ matrix.specs || format('--shard={0}/{1}', matrix.shard, strategy.job-total) }}
# Args for actual test command runner
CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }}
QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }}
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
@ -158,22 +121,17 @@ jobs:
N8N_ENCRYPTION_KEY: ${{ secrets.N8N_ENCRYPTION_KEY }}
N8N_TEST_ENV: ${{ inputs.n8n-env }}
- name: Upload Failure Artifacts
if: ${{ failure() && inputs.upload-failure-artifacts }}
- name: Upload Shard Artifacts
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: playwright-report-shard-${{ matrix.shard }}
name: ${{ inputs.artifact-prefix }}-shard-${{ matrix.shard }}
path: |
packages/testing/playwright/test-results/
packages/testing/playwright/playwright-report/
retention-days: 7
- name: Cleanup cached CI images
if: ${{ inputs.test-mode == 'docker-pull' }}
continue-on-error: true
run: |
docker images --format '{{.Repository}}:{{.Tag}}' | grep -E 'ghcr\.io/n8n-io/(n8n|runners):(ci|pr)-' | xargs -r docker rmi || true
docker system prune -f || true
packages/testing/playwright/.nyc_output/
retention-days: 1
if-no-files-found: ignore
- name: Cancel Currents run if workflow is cancelled
if: ${{ cancelled() }}

View File

@ -12,17 +12,30 @@ on:
default: 'master'
jobs:
e2e-vm-expressions:
uses: ./.github/workflows/test-e2e-ci-reusable.yml
prepare-docker:
uses: ./.github/workflows/prepare-docker-reusable.yml
with:
branch: ${{ github.event_name == 'schedule' && 'master' || inputs.branch }}
secrets: inherit
e2e:
name: E2E
needs: [prepare-docker]
uses: ./.github/workflows/test-e2e-reusable.yml
with:
branch: ${{ github.event_name == 'schedule' && 'master' || inputs.branch }}
test-mode: docker-artifact
test-command: pnpm --filter=n8n-playwright test:container:multi-main:e2e
workers: '1'
pre-generated-matrix: '[{"shard":1},{"shard":2},{"shard":3},{"shard":4},{"shard":5},{"shard":6},{"shard":7},{"shard":8},{"shard":9},{"shard":10},{"shard":11},{"shard":12},{"shard":13},{"shard":14},{"shard":15},{"shard":16}]'
n8n-env: '{"N8N_EXPRESSION_ENGINE":"vm"}'
artifact-prefix: vm-expressions
secrets: inherit
notify-on-failure:
name: Notify Slack on failure
runs-on: ubuntu-slim
needs: [e2e-vm-expressions]
needs: [e2e]
if: failure() && github.event_name == 'schedule'
steps:
- uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0

View File

@ -48,15 +48,16 @@ jobs:
- name: Generate experiment name
id: experiment
env:
PREFIX: ${{ inputs.experiment_name_prefix }}
BRANCH: ${{ inputs.branch }}
run: |
DATE=$(date +%Y_%m_%d)
PREFIX="${{ inputs.experiment_name_prefix }}"
if [ -n "$PREFIX" ]; then
NAME="${PREFIX}_${DATE}"
else
# Extract ticket ID from branch name (e.g., AI-1234 from ai-1234-feature-name)
BRANCH="${{ inputs.branch }}"
TICKET=$(echo "$BRANCH" | grep -oE '^[Aa][Ii]-[0-9]+' | tr '[:lower:]' '[:upper:]' || true)
if [ -n "$TICKET" ]; then
NAME="${TICKET}_${DATE}"
@ -95,14 +96,23 @@ jobs:
- name: Run Evaluations
working-directory: packages/@n8n/ai-workflow-builder.ee/evaluations
env:
SUITE: ${{ inputs.suite }}
DATASET: ${{ inputs.dataset }}
REPETITIONS: ${{ inputs.repetitions }}
JUDGES: ${{ inputs.judges }}
CONCURRENCY: ${{ inputs.concurrency }}
EXPERIMENT_NAME: ${{ steps.experiment.outputs.name }}
WEBHOOK_URL_ARG: ${{ secrets.EVALS_WEBHOOK_URL && format('--webhook-url={0}', secrets.EVALS_WEBHOOK_URL) || '' }}
WEBHOOK_SECRET_ARG: ${{ secrets.EVALS_WEBHOOK_SECRET && format('--webhook-secret={0}', secrets.EVALS_WEBHOOK_SECRET) || '' }}
run: |
pnpm eval \
--suite "${{ inputs.suite }}" \
--suite "$SUITE" \
--backend langsmith \
--dataset "${{ inputs.dataset }}" \
--repetitions ${{ inputs.repetitions }} \
--judges ${{ inputs.judges }} \
--concurrency ${{ inputs.concurrency }} \
--name "${{ steps.experiment.outputs.name }}" \
${{ secrets.EVALS_WEBHOOK_URL && format('--webhook-url "{0}"', secrets.EVALS_WEBHOOK_URL) || '' }} \
${{ secrets.EVALS_WEBHOOK_SECRET && format('--webhook-secret "{0}"', secrets.EVALS_WEBHOOK_SECRET) || '' }}
--dataset "$DATASET" \
--repetitions "$REPETITIONS" \
--judges "$JUDGES" \
--concurrency "$CONCURRENCY" \
--name "$EXPERIMENT_NAME" \
"$WEBHOOK_URL_ARG" \
"$WEBHOOK_SECRET_ARG"

View File

@ -0,0 +1,281 @@
name: 'Test: Instance AI Exec Evals'
on:
workflow_call:
inputs:
branch:
description: 'GitHub branch to test'
required: false
type: string
default: 'master'
filter:
description: 'Filter test cases by name (e.g. "contact-form")'
required: false
type: string
default: ''
workflow_dispatch:
inputs:
branch:
description: 'GitHub branch to test'
required: false
default: 'master'
filter:
description: 'Filter test cases by name (e.g. "contact-form")'
required: false
default: ''
jobs:
run-evals:
name: 'Run Evals'
runs-on: blacksmith-4vcpu-ubuntu-2204
timeout-minutes: 45
env:
# Each port hosts an independent n8n container. The eval CLI's
# work-stealing allocator dispatches builds across them, capped per-lane.
# 9 lanes on 4vcpu — builds are LLM-bound so CPU headroom is sufficient;
# bump back to 8vcpu if contention shows up.
LANE_PORTS: '5678,5679,5680,5681,5682,5683,5684,5685,5686'
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1
- name: Setup Environment
uses: ./.github/actions/setup-nodejs
with:
build-command: 'pnpm build'
# Cache populated by prepare-docker; fallback covers PRs that only touch this workflow file.
- name: Load n8n Docker image
id: load-image
continue-on-error: true
uses: ./.github/actions/load-n8n-docker
- name: Build Docker image (fallback on cache miss)
if: steps.load-image.outcome == 'failure'
run: pnpm build:docker
env:
INCLUDE_TEST_CONTROLLER: 'true'
- name: Start n8n containers
env:
EVALS_ANTHROPIC_KEY: ${{ secrets.EVALS_ANTHROPIC_KEY }}
N8N_LICENSE_ACTIVATION_KEY: ${{ secrets.N8N_LICENSE_ACTIVATION_KEY }}
N8N_LICENSE_CERT: ${{ secrets.N8N_LICENSE_CERT }}
N8N_ENCRYPTION_KEY: ${{ secrets.N8N_ENCRYPTION_KEY }}
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
run: |
IFS=',' read -ra PORTS <<< "$LANE_PORTS"
for i in "${!PORTS[@]}"; do
port="${PORTS[$i]}"
docker run -d --name "n8n-eval-$((i+1))" \
-e E2E_TESTS=true \
-e N8N_ENABLED_MODULES=instance-ai \
-e N8N_AI_ENABLED=true \
-e N8N_INSTANCE_AI_MODEL_API_KEY="$EVALS_ANTHROPIC_KEY" \
-e N8N_AI_ASSISTANT_BASE_URL="" \
-e N8N_INSTANCE_AI_SANDBOX_ENABLED=true \
-e N8N_INSTANCE_AI_SANDBOX_PROVIDER=daytona \
-e DAYTONA_API_URL=https://app.daytona.io/api \
-e DAYTONA_API_KEY="$DAYTONA_API_KEY" \
-e N8N_LICENSE_ACTIVATION_KEY="$N8N_LICENSE_ACTIVATION_KEY" \
-e N8N_LICENSE_CERT="$N8N_LICENSE_CERT" \
-e N8N_ENCRYPTION_KEY="$N8N_ENCRYPTION_KEY" \
-p "$port:5678" \
n8nio/n8n:local
done
# 120s budget per port: containers booting in parallel on a shared
# 4vcpu runner contend for CPU/disk during n8n's startup (DB migrations,
# license init), so each takes longer than a solo boot.
for port in "${PORTS[@]}"; do
ready=false
for i in $(seq 1 120); do
if curl -s "http://localhost:$port/healthz/readiness" -o /dev/null -w "%{http_code}" | grep -q 200; then
echo "n8n on port $port ready after ${i}s"
ready=true
break
fi
sleep 1
done
if [ "$ready" != "true" ]; then
echo "::error::n8n on port $port failed to start within 120s"
for n in $(docker ps -aq --filter "name=n8n-eval-"); do
echo "Logs for $n:"
docker logs "$n" --tail 30 || true
done
exit 1
fi
done
- name: Create test users
run: |
IFS=',' read -ra PORTS <<< "$LANE_PORTS"
for port in "${PORTS[@]}"; do
curl -sf -X POST "http://localhost:$port/rest/e2e/reset" \
-H "Content-Type: application/json" \
-d '{
"owner":{"email":"nathan@n8n.io","password":"PlaywrightTest123","firstName":"Eval","lastName":"Owner"},
"admin":{"email":"admin@n8n.io","password":"PlaywrightTest123","firstName":"Admin","lastName":"User"},
"members":[],
"chat":{"email":"chat@n8n.io","password":"PlaywrightTest123","firstName":"Chat","lastName":"User"}
}'
done
# Belt-and-suspenders: env vars set sandbox config but persisted admin
# settings can override. Per-lane assertion catches env-injection hiccups
# or unexpected DB-side state. A single misconfigured lane would
# silently route some builds through tool mode and pollute results.
- name: Assert sandbox is enabled on every lane
run: |
IFS=',' read -ra PORTS <<< "$LANE_PORTS"
bad=0
for i in "${!PORTS[@]}"; do
port="${PORTS[$i]}"
lane="$((i+1))"
curl -sf -X POST "http://localhost:$port/rest/login" \
-H "Content-Type: application/json" \
-d '{"emailOrLdapLoginId":"nathan@n8n.io","password":"PlaywrightTest123"}' \
-c "/tmp/cookies-$port.txt" -o /dev/null
cfg=$(curl -sf -b "/tmp/cookies-$port.txt" \
"http://localhost:$port/rest/instance-ai/settings" \
| jq -r '.data | "\(.sandboxEnabled) \(.sandboxProvider)"')
if [ "$cfg" != "true daytona" ]; then
echo "::error::lane $lane (port $port): expected 'true daytona', got '$cfg'"
bad=$((bad+1))
else
echo " lane $lane: sandboxEnabled=true sandboxProvider=daytona ok"
fi
done
if [ "$bad" -gt 0 ]; then
echo "::error::$bad lane(s) misconfigured - eval would mix sandbox + tool-mode builds"
exit 1
fi
- name: Run Instance AI Evals
continue-on-error: true
working-directory: packages/@n8n/instance-ai
env:
N8N_INSTANCE_AI_MODEL_API_KEY: ${{ secrets.EVALS_ANTHROPIC_KEY }}
LANGSMITH_TRACING: 'true'
LANGSMITH_ENDPOINT: ${{ secrets.EVALS_LANGSMITH_ENDPOINT }}
LANGSMITH_API_KEY: ${{ secrets.EVALS_LANGSMITH_API_KEY }}
LANGSMITH_REVISION_ID: ${{ github.sha }}
LANGSMITH_BRANCH: ${{ github.head_ref || github.ref_name }}
run: |
IFS=',' read -ra PORTS <<< "$LANE_PORTS"
URLS=()
for port in "${PORTS[@]}"; do
URLS+=("http://localhost:$port")
done
BASE_URLS=$(IFS=,; printf '%s' "${URLS[*]}")
pnpm eval:instance-ai \
--base-url "$BASE_URLS" \
--concurrency 32 \
--verbose \
--iterations 5 \
${{ inputs.filter && format('--filter "{0}"', inputs.filter) || '' }}
# Captures sandbox/builder/Daytona signals that surface during the eval
# (after migrations finish). Two layers of secret-leak defense:
#
# 1. Filter to specific diagnostic patterns — never tail raw output.
# The grep allowlist scopes the log surface to lines we care
# about for debugging (sandbox lifecycle, builder, errors).
#
# 2. Re-register secrets via ::add-mask:: so any line that does
# match the allowlist has the secret values replaced with ***
# before reaching the GH Actions log. GitHub auto-masks
# ${{ secrets.X }} references, but the masking is fragile
# against transformed or split values; explicit registration
# reinforces it.
#
# Runs even on eval failure so we have the post-mortem regardless.
- name: Capture n8n container logs (debug)
if: ${{ always() }}
env:
EVALS_ANTHROPIC_KEY: ${{ secrets.EVALS_ANTHROPIC_KEY }}
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
N8N_LICENSE_ACTIVATION_KEY: ${{ secrets.N8N_LICENSE_ACTIVATION_KEY }}
N8N_LICENSE_CERT: ${{ secrets.N8N_LICENSE_CERT }}
N8N_ENCRYPTION_KEY: ${{ secrets.N8N_ENCRYPTION_KEY }}
run: |
# Layer 2 — defense in depth: explicitly mask each secret's value.
# ::add-mask:: is a single-line workflow command. Multi-line secrets
# (e.g. N8N_LICENSE_CERT is PEM-encoded) must be masked one line at
# a time, otherwise only the first line is registered.
for v in "$EVALS_ANTHROPIC_KEY" "$DAYTONA_API_KEY" \
"$N8N_LICENSE_ACTIVATION_KEY" "$N8N_LICENSE_CERT" \
"$N8N_ENCRYPTION_KEY"; do
[ -z "$v" ] && continue
while IFS= read -r line; do
[ -n "$line" ] && echo "::add-mask::$line"
done <<< "$v"
done
# Layer 1 — accuracy filter: only surface diagnostic signals.
# `tail -100` after the filter so we get the LATEST matching lines
# (post-eval failure signal), not the earliest startup-time ones.
SIGNALS='sandbox|builder|daytona|instance.?ai|error|warn|reject|exception|fail'
for c in $(docker ps -aq --filter "name=n8n-eval-"); do
name=$(docker inspect --format '{{.Name}}' "$c" | sed 's|^/||')
echo ""
echo "============================================================"
echo "=== $name (filtered diagnostic signals, last 100 lines) ==="
echo "============================================================"
docker logs "$c" 2>&1 \
| grep -ivE 'migration' \
| grep -iE "$SIGNALS" \
| tail -100 \
|| true
done
- name: Stop n8n containers
if: ${{ always() }}
run: |
mapfile -t ids < <(docker ps -aq --filter "name=n8n-eval-")
if [ "${#ids[@]}" -gt 0 ]; then
docker stop "${ids[@]}" 2>/dev/null || true
docker rm "${ids[@]}" 2>/dev/null || true
fi
- name: Post eval results to PR
if: ${{ always() && github.event_name == 'pull_request' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# The eval CLI writes the full PR comment as eval-pr-comment.md
# (see comparison/format.ts:formatComparisonMarkdown). It includes
# the alert, aggregate, comparison sections, per-test-case results
# collapsed, and failure details collapsed. CI just relays it.
COMMENT_FILE="packages/@n8n/instance-ai/eval-pr-comment.md"
if [ ! -f "$COMMENT_FILE" ]; then
echo "No PR comment file found (eval likely cancelled before writing results)"
exit 0
fi
cp "$COMMENT_FILE" /tmp/eval-comment.md
# Find and update existing eval comment, or create new one
COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
--jq '.[] | select(.body | startswith("### Instance AI Workflow Eval")) | .id' | tail -1)
if [ -n "$COMMENT_ID" ]; then
gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" -X PATCH -F body=@/tmp/eval-comment.md
else
gh pr comment "${{ github.event.pull_request.number }}" --body-file /tmp/eval-comment.md
fi
- name: Upload Results
if: ${{ always() }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: instance-ai-workflow-eval-results
path: |
packages/@n8n/instance-ai/eval-results.json
packages/@n8n/instance-ai/.data/workflow-eval-report.html
retention-days: 14

View File

@ -29,5 +29,5 @@ jobs:
- name: Build and Test
uses: ./.github/actions/setup-nodejs
with:
build-command: pnpm lint
build-command: pnpm lint:ci
node-version: ${{ inputs.nodeVersion }}

View File

@ -34,4 +34,4 @@ jobs:
skip: 'release/**'
onlyChanged: true
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
exitZeroOnChanges: false
exitZeroOnChanges: true

View File

@ -20,7 +20,8 @@ jobs:
cloudflare:
name: Cloudflare Pages
if: |
!contains(github.event.pull_request.labels.*.name, 'community')
!contains(github.event.pull_request.labels.*.name, 'community') &&
github.repository == 'n8n-io/n8n'
runs-on: blacksmith-2vcpu-ubuntu-2204
permissions:
contents: read

View File

@ -17,8 +17,8 @@ on:
description: 'Encryption key for n8n operations.'
required: true
CURRENTS_RECORD_KEY:
description: 'Currents record key for uploading test results.'
required: true
description: 'Currents record key for test reporting. Empty on fork PRs.'
required: false
env:
NODE_OPTIONS: --max-old-space-size=3072

View File

@ -30,16 +30,20 @@ jobs:
- name: Approve PR (as the App)
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ inputs.pull-request-number }}
REPOSITORY: ${{ github.repository }}
run: |
gh pr review "${{ inputs.pull-request-number }}" \
gh pr review "$PR_NUMBER" \
--approve \
--repo "${{ github.repository }}"
--repo "$REPOSITORY"
- name: Enable auto-merge (merge when checks pass)
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ inputs.pull-request-number }}
REPOSITORY: ${{ github.repository }}
run: |
gh pr merge "${{ inputs.pull-request-number }}" \
gh pr merge "$PR_NUMBER" \
--auto \
--squash \
--repo "${{ github.repository }}"
--repo "$REPOSITORY"

View File

@ -131,6 +131,8 @@ jobs:
prompt: ${{ env.CLAUDE_PROMPT }}
show_full_output: ${{ inputs.suppress_output != true }}
display_report: false
plugin_marketplaces: "./.claude/plugins/n8n"
plugins: "n8n@n8n"
settings: |
{
"permissions": {
@ -167,8 +169,10 @@ jobs:
- name: Push branch
if: always()
env:
REF: ${{ inputs.ref }}
run: |
if ! git diff --quiet "${{ inputs.ref }}" 2>/dev/null; then
if ! git diff --quiet "$REF" 2>/dev/null; then
git push -u origin "$BRANCH_NAME"
echo "::notice::Changes pushed to branch $BRANCH_NAME"
else

View File

@ -31,4 +31,6 @@ jobs:
install-command: pnpm install --frozen-lockfile --dir ./.github/scripts --ignore-workspace
- name: Ensure release-candidate branches
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
run: node ./.github/scripts/ensure-release-candidate-branches.mjs

View File

@ -18,7 +18,8 @@ jobs:
name: Post Metrics Comment
if: >-
github.event_name == 'pull_request' &&
!github.event.pull_request.head.repo.fork
!github.event.pull_request.head.repo.fork &&
github.repository == 'n8n-io/n8n'
runs-on: ubuntu-slim
continue-on-error: true
permissions:
@ -34,7 +35,9 @@ jobs:
QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }}
QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }}
GITHUB_TOKEN: ${{ github.token }}
METRICS: ${{ inputs.metrics }}
BASELINE_DAYS: ${{ inputs.baseline-days }}
run: |
node .github/scripts/post-qa-metrics-comment.mjs \
--metrics "${{ inputs.metrics }}" \
--baseline-days "${{ inputs.baseline-days }}"
--metrics "$METRICS" \
--baseline-days "$BASELINE_DAYS"

7
.gitignore vendored
View File

@ -25,6 +25,7 @@ packages/**/.turbo
*.swp
CHANGELOG-*.md
*.mdx
!packages/frontend/@n8n/design-system/**/*.mdx
build-storybook.log
build.log
*.junit.xml
@ -33,6 +34,10 @@ test-results.json
*.0x
packages/testing/playwright/playwright-report
packages/testing/playwright/test-results
packages/testing/playwright/eval-results.json
packages/@n8n/instance-ai/eval-results.json
packages/@n8n/instance-ai/.eval-output/
packages/@n8n/instance-ai/eval-pr-comment.md
packages/testing/playwright/.playwright-browsers
packages/testing/playwright/.playwright-cli
test-results/
@ -57,6 +62,8 @@ packages/cli/src/commands/export/outputs
.data/
.claude/settings.local.json
.claude/plans/
.claude/worktrees/
.claude/specs/
.cursor/plans/
.superset
.conductor

View File

@ -81,6 +81,7 @@ The monorepo is organized into these key packages:
- **`packages/@n8n/i18n`**: Internationalization for UI text
- **`packages/nodes-base`**: Built-in nodes for integrations
- **`packages/@n8n/nodes-langchain`**: AI/LangChain nodes
- **`packages/@n8n/instance-ai`**: "AI Assistant" in the UI, "Instance AI" in code — AI assistant backend. See its `CLAUDE.md` for architecture docs.
- **`@n8n/design-system`**: Vue component library for UI consistency
- **`@n8n/config`**: Centralized configuration management
@ -145,14 +146,11 @@ const children = getChildNodes(workflow.connections, 'NodeName', 'main', 1);
- Import from appropriate error classes in each package
### Frontend Development
- Refer to `packages/frontend/AGENTS.md`
- **All UI text must use i18n** - add translations to `@n8n/i18n` package
- **Use CSS variables directly** - never hardcode spacing as px values
- **data-testid must be a single value** (no spaces or multiple values)
- For style changes and design-system updates, follow
`.agents/design-system-style-rules.md`
When implementing CSS, refer to @packages/frontend/CLAUDE.md for guidelines on
CSS variables and styling conventions.
- Always use `design-system-rules` skill in reviews
### Testing Guidelines
- **Always work from within the package directory** when running tests

View File

@ -1,3 +1,485 @@
# [2.21.0](https://github.com/n8n-io/n8n/compare/n8n@2.20.0...n8n@2.21.0) (2026-05-12)
### Bug Fixes
* Add warning to Computer Use install modal ([#30094](https://github.com/n8n-io/n8n/issues/30094)) ([ecf96ad](https://github.com/n8n-io/n8n/commit/ecf96ad30c8d29641db07cd78885ea28aff26199))
* **ai-builder:** Allow restoring archived workflows from Instance AI ([#29813](https://github.com/n8n-io/n8n/issues/29813)) ([a33a89a](https://github.com/n8n-io/n8n/commit/a33a89a215d6cef39895858bf36c00c15abfdd9d))
* **ai-builder:** Preserve collected planning context ([#29916](https://github.com/n8n-io/n8n/issues/29916)) ([5e3aa1a](https://github.com/n8n-io/n8n/commit/5e3aa1a726e903387344d3a4ed51e97811e4ff02))
* **ai-builder:** Resolve HitlTool variants to base node in get_node_types ([#29731](https://github.com/n8n-io/n8n/issues/29731)) ([ed9471a](https://github.com/n8n-io/n8n/commit/ed9471a5321747bbca003bee7d6a37d54bb79cb2))
* **Airtable Node:** Fix typecast option dropping attachment field updates ([#29556](https://github.com/n8n-io/n8n/issues/29556)) ([0cafc71](https://github.com/n8n-io/n8n/commit/0cafc717a274053f698e988d6f44a27a8b936e83))
* Align undici override across major versions ([#30028](https://github.com/n8n-io/n8n/issues/30028)) ([6b893b4](https://github.com/n8n-io/n8n/commit/6b893b45a0d05dfb08ea7b732f775c28b6ccf801))
* **Calendly Trigger Node:** Use API v2 for webhook subscriptions ([#29771](https://github.com/n8n-io/n8n/issues/29771)) ([0edcdcf](https://github.com/n8n-io/n8n/commit/0edcdcfe8529b6296f1a1f0d8b8af3841a14a466))
* **core:** Activate agent chat integrations on every main ([#30029](https://github.com/n8n-io/n8n/issues/30029)) ([6f4f0a0](https://github.com/n8n-io/n8n/commit/6f4f0a0303e1f0f0cd57a5b0dab08347010b7241))
* **core:** Add configurable retries and error details to S3 ([#28309](https://github.com/n8n-io/n8n/issues/28309)) ([e2576ca](https://github.com/n8n-io/n8n/commit/e2576ca25bc973b315bdcbff1a1b2d3309bc647d))
* **core:** Add ESLint rule to prevent error instances in toThrow assertions ([#29889](https://github.com/n8n-io/n8n/issues/29889)) ([75ed71c](https://github.com/n8n-io/n8n/commit/75ed71c00142e8bbdfb851691d5fc3de3cfada36))
* **core:** Add liveness timeouts for Instance AI ([#30145](https://github.com/n8n-io/n8n/issues/30145)) ([52a4bcb](https://github.com/n8n-io/n8n/commit/52a4bcb23a9398b1327acd0ec39df7a9e00b48b6))
* **core:** Add support for context establishment hooks in webhook mode ([#29893](https://github.com/n8n-io/n8n/issues/29893)) ([04e9b25](https://github.com/n8n-io/n8n/commit/04e9b258a887c07b62774f09e3921932038a3984))
* **core:** Add workflow structure validation ([#29699](https://github.com/n8n-io/n8n/issues/29699)) ([bec74ae](https://github.com/n8n-io/n8n/commit/bec74aeb4fda198853b3ea82ed135a1db3ba4988))
* **core:** Advance Postgres IDENTITY sequences after entity import ([#29762](https://github.com/n8n-io/n8n/issues/29762)) ([ca33060](https://github.com/n8n-io/n8n/commit/ca33060e0bd30c6d077f8dd18ca8492d50c06a92))
* **core:** Agent sessions correctly quoting columns in queries for Postgres ([#29999](https://github.com/n8n-io/n8n/issues/29999)) ([9f92005](https://github.com/n8n-io/n8n/commit/9f92005938a1b481b89558b4e82a198da6ec4e8c))
* **core:** Agents called from workflows use the workflows owner/user ID for calling further workflows through the agent ([#30242](https://github.com/n8n-io/n8n/issues/30242)) ([9072ee3](https://github.com/n8n-io/n8n/commit/9072ee3beb1789f34008cb0f85f361dcac8cae26))
* **core:** Allow GIT_SSH_COMMAND in simple-git after 3.36.0 upgrade ([#29894](https://github.com/n8n-io/n8n/issues/29894)) ([f42be90](https://github.com/n8n-io/n8n/commit/f42be9030e7f549da5ed6dc3902d058c2ebbadcb))
* **core:** Allow profile edits when SSO is no longer active ([#29765](https://github.com/n8n-io/n8n/issues/29765)) ([2714f00](https://github.com/n8n-io/n8n/commit/2714f001218d1323233c1920c94ed02a5ce8dcf1))
* **core:** Allow same-domain redirects in instance-ai web research (TRUST-73) ([#30107](https://github.com/n8n-io/n8n/issues/30107)) ([3123f25](https://github.com/n8n-io/n8n/commit/3123f2551be75fb282628b9106b060975fb983fc))
* **core:** Always create instance-ai sandbox workspace dirs (TRUST-79) ([#30106](https://github.com/n8n-io/n8n/issues/30106)) ([5e88748](https://github.com/n8n-io/n8n/commit/5e887483344daad5e11bee97d3315a9b2b38d0c9))
* **core:** Avoid MCP get_execution hang on circular references ([#30051](https://github.com/n8n-io/n8n/issues/30051)) ([60e23e1](https://github.com/n8n-io/n8n/commit/60e23e10e01f20f73fb1c61d74b5ca44a4c677f6))
* **core:** Check npm provenance in community package scanner ([#29667](https://github.com/n8n-io/n8n/issues/29667)) ([804f51c](https://github.com/n8n-io/n8n/commit/804f51cf0d8411b4d4df6f593fdea787b97fad51))
* **core:** Clarify 0-based indexing in workflow SDK prompts and JSDoc ([#29734](https://github.com/n8n-io/n8n/issues/29734)) ([fba873c](https://github.com/n8n-io/n8n/commit/fba873c37e76f01d28443c5276b2d92bd333602a))
* **core:** Clarify agent builder prompt guidance ([#30127](https://github.com/n8n-io/n8n/issues/30127)) ([75646c4](https://github.com/n8n-io/n8n/commit/75646c45271831bf8d03653baf024d201d5fae6d))
* **core:** Defer credential setup during workflow builds ([#30181](https://github.com/n8n-io/n8n/issues/30181)) ([bb73952](https://github.com/n8n-io/n8n/commit/bb73952fcc9aff4eed0af6bb99fb10f65d48df3d))
* **core:** Emit missing auth audit events for OIDC and SSO-restricted login ([#29856](https://github.com/n8n-io/n8n/issues/29856)) ([dd812c5](https://github.com/n8n-io/n8n/commit/dd812c5010ca28ca38c238bfa8c57fe39ac816d5))
* **core:** Export boolean CSV values as true/false for Data Tables ([#30007](https://github.com/n8n-io/n8n/issues/30007)) ([94d91e1](https://github.com/n8n-io/n8n/commit/94d91e13bfcaf360099a0a3816b0025502b145f4))
* **core:** Filter WaitTracker to only poll waiting executions ([#29898](https://github.com/n8n-io/n8n/issues/29898)) ([5c7921f](https://github.com/n8n-io/n8n/commit/5c7921f71c95d97f6730e6b28b06947b1cfbaa23))
* **core:** Fix duplicate task request on runner defer ([#28315](https://github.com/n8n-io/n8n/issues/28315)) ([80c8a6c](https://github.com/n8n-io/n8n/commit/80c8a6c2fdc97624c9b4b3e97b8ff20aca641552))
* **core:** Harden axios error handling against non-string error stack ([#29100](https://github.com/n8n-io/n8n/issues/29100)) ([2dbf02e](https://github.com/n8n-io/n8n/commit/2dbf02e63e5ddee8d9e4a94f2ad3cd1f5321f2a7))
* **core:** Improve AI chat file upload handling and error states ([#29701](https://github.com/n8n-io/n8n/issues/29701)) ([afe119b](https://github.com/n8n-io/n8n/commit/afe119be1409ac2cb198f7a41dc12ed25f5cf106))
* **core:** Improve documentation usage in mcp tools ([#30210](https://github.com/n8n-io/n8n/issues/30210)) ([e8827cd](https://github.com/n8n-io/n8n/commit/e8827cd6e8ff3eb03ceab6965574bacf10c719d0))
* **core:** Initialise encryption key proxy on worker and webhook instances ([#29912](https://github.com/n8n-io/n8n/issues/29912)) ([ae57e60](https://github.com/n8n-io/n8n/commit/ae57e606b4f5cf691bceb01489e5991cf31911ef))
* **core:** Inline AI_NODE_SDK_VERSION to save memory by not loading @n8n/ai-utilities on boot ([#30113](https://github.com/n8n-io/n8n/issues/30113)) ([f709e53](https://github.com/n8n-io/n8n/commit/f709e5382448926e15e36571aa9fd32db238e36d))
* **core:** Persist agent chat draft across modes and hide unfinished tool-approval toggle ([#30123](https://github.com/n8n-io/n8n/issues/30123)) ([7094b48](https://github.com/n8n-io/n8n/commit/7094b48c9444024af6c14b72b49b47b555db52ef))
* **core:** Preserve node positions on AI workflow updates ([#29850](https://github.com/n8n-io/n8n/issues/29850)) ([f2764f0](https://github.com/n8n-io/n8n/commit/f2764f04c0e663268fe40737c55c8c1a0f33173b))
* **core:** Prevent proxy layer accumulation in ObservableObject ([#30129](https://github.com/n8n-io/n8n/issues/30129)) ([0a76135](https://github.com/n8n-io/n8n/commit/0a761355c4836433c379ee8933c0198621879ae0))
* **core:** Propagate waitTill from worker to main in scaling mode ([#30099](https://github.com/n8n-io/n8n/issues/30099)) ([3702ff8](https://github.com/n8n-io/n8n/commit/3702ff8eb31547d51e3b56b484bf6a731296f9cf))
* **core:** Scope credential resolution ([#30156](https://github.com/n8n-io/n8n/issues/30156)) ([174f0f8](https://github.com/n8n-io/n8n/commit/174f0f805e0d5715d2d80e5c0282a94b79e9a390))
* **core:** Simple-git update broke https connection ([#29998](https://github.com/n8n-io/n8n/issues/29998)) ([01300e9](https://github.com/n8n-io/n8n/commit/01300e9b9b7e0f80f1852c5e1e4b3df9a42404c4))
* **core:** Simplify Slack redirect URL verification process for agents ([#30033](https://github.com/n8n-io/n8n/issues/30033)) ([8201281](https://github.com/n8n-io/n8n/commit/820128196cf550ab8cf371fbebb3457b9fd35d22))
* **core:** Skip disabled tool nodes when mapping AI Agent tool sources ([#29460](https://github.com/n8n-io/n8n/issues/29460)) ([bd7eeb7](https://github.com/n8n-io/n8n/commit/bd7eeb7bc89032b9a0db467cb53f37bfef71647e))
* **core:** Skip unknown fixedCollection keys instead of throwing ([#29689](https://github.com/n8n-io/n8n/issues/29689)) ([a30772c](https://github.com/n8n-io/n8n/commit/a30772c933544d06b560a3c66ec69cd4f7b8574f))
* **core:** Stop applying node-defined sensitive output fields to runtime data ([#30198](https://github.com/n8n-io/n8n/issues/30198)) ([f4e8088](https://github.com/n8n-io/n8n/commit/f4e8088cb8df24443eec0482e2c58346c1e30016))
* **core:** Stop logging password reset token values ([#29405](https://github.com/n8n-io/n8n/issues/29405)) ([bc8d196](https://github.com/n8n-io/n8n/commit/bc8d196931b35118ca6078a5845e8549bbba7e6b))
* **core:** Support type filters on global credential lookups ([#30002](https://github.com/n8n-io/n8n/issues/30002)) ([8e0f37d](https://github.com/n8n-io/n8n/commit/8e0f37d100b45d4105ca168bb8f62ec2c1328cf2))
* **core:** Throw on bare OutputSelector passed to .add()/.to() ([#29736](https://github.com/n8n-io/n8n/issues/29736)) ([60a5122](https://github.com/n8n-io/n8n/commit/60a51229e0db92a00788eb12586ea6376276645d))
* **core:** Validate AI builder credential IDs before save ([#30070](https://github.com/n8n-io/n8n/issues/30070)) ([ceaebc6](https://github.com/n8n-io/n8n/commit/ceaebc6cbe7cde2269aee4be6966d021f136f9c6))
* Correct connect.html path in browser extension ([#29714](https://github.com/n8n-io/n8n/issues/29714)) ([9b3b29b](https://github.com/n8n-io/n8n/commit/9b3b29b5058da42ec736c14cc8af5726b2a64e4b))
* **EditImage Node:** Fix composite operation failing with stream empty buffer ([#30088](https://github.com/n8n-io/n8n/issues/30088)) ([0cc163b](https://github.com/n8n-io/n8n/commit/0cc163b7dcccbfa68c065faa466b2b50f21c4a97))
* **editor:** Add expand/collapse to chat panel in Agents ([#30069](https://github.com/n8n-io/n8n/issues/30069)) ([f87094c](https://github.com/n8n-io/n8n/commit/f87094cf6e5efe7c89ef16c4253525091479b356))
* **editor:** Disable chat during interactive agent choices ([#30111](https://github.com/n8n-io/n8n/issues/30111)) ([8171cf0](https://github.com/n8n-io/n8n/commit/8171cf0b32ee5aa74dd240bb8f99a3250e428217))
* **editor:** Fix Agents styling issues from merge regression ([#30032](https://github.com/n8n-io/n8n/issues/30032)) ([478d499](https://github.com/n8n-io/n8n/commit/478d4998a8055a3d5f81b93120d67282546f125a))
* **editor:** Fix collapse/expand for Chat sidebar ([#29378](https://github.com/n8n-io/n8n/issues/29378)) ([ee847d1](https://github.com/n8n-io/n8n/commit/ee847d1624636914323b8b06f145ae811101528f))
* **editor:** Improve sidebar new resource menu UX ([#29597](https://github.com/n8n-io/n8n/issues/29597)) ([d5af542](https://github.com/n8n-io/n8n/commit/d5af542f254ba4846f3f393404e24bc5ec998283))
* **editor:** Make sure trimmed placeholder never reaches backend ([#29842](https://github.com/n8n-io/n8n/issues/29842)) ([f7c7acc](https://github.com/n8n-io/n8n/commit/f7c7acc2441481235d81a38ea14ed637546d3b40))
* **editor:** Match input height with mode selector in resource locator ([#30075](https://github.com/n8n-io/n8n/issues/30075)) ([277431b](https://github.com/n8n-io/n8n/commit/277431b88b195d92a32e35a7df7f8df907d9cb44))
* **editor:** Polish encryption keys settings page ([#30008](https://github.com/n8n-io/n8n/issues/30008)) ([5cbd2dd](https://github.com/n8n-io/n8n/commit/5cbd2dd1e9a66cb1d00d89191395f2b417c7a08b))
* **editor:** Preserve decimal suffix when duplicating a node ([#29541](https://github.com/n8n-io/n8n/issues/29541)) ([08a36d7](https://github.com/n8n-io/n8n/commit/08a36d7515eda29acd6c5e03f7968d4896465b3d))
* **editor:** Refresh node icon when diff sidebar selection changes ([#29816](https://github.com/n8n-io/n8n/issues/29816)) ([ff41613](https://github.com/n8n-io/n8n/commit/ff41613533980f8f2a0ff7baef5fd2a63d981636))
* **editor:** Rename canvas header dropdown action to Description ([#29719](https://github.com/n8n-io/n8n/issues/29719)) ([49e7b05](https://github.com/n8n-io/n8n/commit/49e7b056b4a21b6341ce1811a597476d37dfa42f))
* **editor:** Rename encryption keys "Type" column to "Status" ([#29966](https://github.com/n8n-io/n8n/issues/29966)) ([e71afed](https://github.com/n8n-io/n8n/commit/e71afedfab84b3b7b88fe9c4e2a36cd31ac6206b))
* **editor:** Render tooltips above popovers ([#29997](https://github.com/n8n-io/n8n/issues/29997)) ([ba5b3d1](https://github.com/n8n-io/n8n/commit/ba5b3d13b116d8e055fe3a4dce1b5349545ff540))
* **editor:** Resolve expressions in 'Go to Sub-workflow' navigation ([#29843](https://github.com/n8n-io/n8n/issues/29843)) ([d6bae35](https://github.com/n8n-io/n8n/commit/d6bae35e8f8f0399cd722606d911ae2c67b60431))
* Fix 15 security issues in fast-xml-builder, basic-ftp, fast-uri and 5 more ([#30169](https://github.com/n8n-io/n8n/issues/30169)) ([267fe49](https://github.com/n8n-io/n8n/commit/267fe49d51b7b8bcc80489b0f9f1a585986bc525))
* **Git Node:** Restore Clone and other operations on simple-git 3.36+ ([#30223](https://github.com/n8n-io/n8n/issues/30223)) ([a8aa955](https://github.com/n8n-io/n8n/commit/a8aa95551e5950fd1920c2cce21cd2739b464266))
* **Google Chat Node:** Clarify message resource name field ([#29964](https://github.com/n8n-io/n8n/issues/29964)) ([55df7cb](https://github.com/n8n-io/n8n/commit/55df7cbd0619e483e7e02207bc5084c715dcb53a))
* **Google Sheets Node:** Reduce duplicate API calls in append operation to avoid quota limits ([#29444](https://github.com/n8n-io/n8n/issues/29444)) ([d63e1ae](https://github.com/n8n-io/n8n/commit/d63e1ae84e767df33c1fc394f646e8ca093aa4a3))
* Handle IMAP fetch errors to prevent instance crash and stuck workflows ([#29469](https://github.com/n8n-io/n8n/issues/29469)) ([46d52ff](https://github.com/n8n-io/n8n/commit/46d52ffc7e719f17db56c433ee97a0b48861ba36))
* **HTTP Request Node:** Validate URL type in older node versions ([#29886](https://github.com/n8n-io/n8n/issues/29886)) ([29a864c](https://github.com/n8n-io/n8n/commit/29a864ca9bcd88e82cf5f998c9ea36d2f81a5dee))
* **MongoDB Node:** Resolve collection parameter per item in write operations ([#29956](https://github.com/n8n-io/n8n/issues/29956)) ([582b6ae](https://github.com/n8n-io/n8n/commit/582b6ae9eaaef6a616233e9bd4eda7230c36eb0a))
* **Notion Node:** Paginate Get Many operations beyond 100-item API cap ([#29690](https://github.com/n8n-io/n8n/issues/29690)) ([d318bc1](https://github.com/n8n-io/n8n/commit/d318bc1e330eeb92d84bc35a2ad9cf6931eccfdf))
* **Notion Node:** Serialize staticData as ISO string in NotionTrigger ([#29688](https://github.com/n8n-io/n8n/issues/29688)) ([d2e1eb3](https://github.com/n8n-io/n8n/commit/d2e1eb30f15c1e2380b815f4d1f62b2b98b23e9a))
* **Notion Node:** Update UI URLs from notion.so to notion.com ahead of domain migration ([#29861](https://github.com/n8n-io/n8n/issues/29861)) ([3593131](https://github.com/n8n-io/n8n/commit/35931319b5b987b7cdd7104accea407fd5390582))
* **Oracle DB Node:** Handle the test failures ([#28341](https://github.com/n8n-io/n8n/issues/28341)) ([0697562](https://github.com/n8n-io/n8n/commit/0697562ac9f1507ca0230d02f462889259a5bdcf))
* Restore broken stdlib calls in Python Code node ([#29776](https://github.com/n8n-io/n8n/issues/29776)) ([a786476](https://github.com/n8n-io/n8n/commit/a7864762ca656c8e636df1ea33750dff604b60ab))
* **RSS Feed Read Node:** Respect proxy settings ([#30059](https://github.com/n8n-io/n8n/issues/30059)) ([2e046d5](https://github.com/n8n-io/n8n/commit/2e046d5b7f2ec4a6fbf00107ee088239f87ce8c5))
* **Salesforce Node:** Fix trigger not firing on repeated record updates ([#29107](https://github.com/n8n-io/n8n/issues/29107)) ([f871d44](https://github.com/n8n-io/n8n/commit/f871d44cabc95fb102af8ba1a9e5d2e314205297))
* **Schedule Node:** Fix hourly intervals that don't divide evenly into 24h ([#29778](https://github.com/n8n-io/n8n/issues/29778)) ([1a22c76](https://github.com/n8n-io/n8n/commit/1a22c762703bed75a18de868a7bfb7c60eacc516))
* **Snowflake Node:** Fix issue with Insert and Update operations not working ([#29339](https://github.com/n8n-io/n8n/issues/29339)) ([4c369e8](https://github.com/n8n-io/n8n/commit/4c369e83f26450395a5a28b6c39a04b2c7650f1f))
* **Supabase Node:** Don't display RPCs in an RLC for the table ([#28146](https://github.com/n8n-io/n8n/issues/28146)) ([78aa0e7](https://github.com/n8n-io/n8n/commit/78aa0e70f21df2533a494c02a3e35ca3ab6ca7b0))
* **Wait Node:** Resolve expressions inside Custom HTML form fields ([#30060](https://github.com/n8n-io/n8n/issues/30060)) ([7c1a771](https://github.com/n8n-io/n8n/commit/7c1a77154ccf1a5f2a11da3cdf0949b2883c85fb))
* **YouTube Node:** Fix misspelled "unlisted" privacy status value in Video Update operation ([#30203](https://github.com/n8n-io/n8n/issues/30203)) ([96b018d](https://github.com/n8n-io/n8n/commit/96b018d3569623e1696a28981b24120a3ceb46d0))
### Features
* **Acuity Scheduling Trigger Node:** Add webhook request verification ([#29261](https://github.com/n8n-io/n8n/issues/29261)) ([da41470](https://github.com/n8n-io/n8n/commit/da41470311a03a15beb5d7361c0385b7dd9acc12))
* Add fully dynamic disclaimer to Quick Connect offer ([#29852](https://github.com/n8n-io/n8n/issues/29852)) ([b6127d8](https://github.com/n8n-io/n8n/commit/b6127d8722ff1bddd9eb5786a6cbd90ce2f98ac1))
* **ai-builder:** Add per-PR eval regression detection vs LangSmith baseline ([#29456](https://github.com/n8n-io/n8n/issues/29456)) ([bbe3e2d](https://github.com/n8n-io/n8n/commit/bbe3e2d1487e06df1e58057ec8c47edb5ad19aa7))
* **ai-builder:** Guarantee user-visible output on terminal states ([#29636](https://github.com/n8n-io/n8n/issues/29636)) ([4d9e624](https://github.com/n8n-io/n8n/commit/4d9e624b4113d06a4cc7a632aed357806349abcb))
* **Asana Trigger Node:** Add webhook request verification ([#29258](https://github.com/n8n-io/n8n/issues/29258)) ([94e4033](https://github.com/n8n-io/n8n/commit/94e403300b44d2f25f4d88dd3d9d1300adfea3bc))
* **Cal Trigger Node:** Add webhook request verification ([#29484](https://github.com/n8n-io/n8n/issues/29484)) ([3276edc](https://github.com/n8n-io/n8n/commit/3276edce10dfc7e59aa12e43fd7fc566f91723c4))
* **Calendly Trigger Node:** Add webhook request verification ([#29482](https://github.com/n8n-io/n8n/issues/29482)) ([e929f9f](https://github.com/n8n-io/n8n/commit/e929f9fbe751742da7f27658ded1ff0101af19d2))
* **core:** Accept merge.input(n) inside ifElse/switch branch targets in workflow-sdk ([#29716](https://github.com/n8n-io/n8n/issues/29716)) ([34f2107](https://github.com/n8n-io/n8n/commit/34f2107071478591a1c98b65576262c40408a157))
* **core:** Add flag to import workflow cli to activate workflow on import ([#29770](https://github.com/n8n-io/n8n/issues/29770)) ([283071e](https://github.com/n8n-io/n8n/commit/283071e6114fd8e8b5063e1ba38daf158bd762d2))
* **core:** Add IP rate limiting to dynamic credential authentication endpoints ([#30199](https://github.com/n8n-io/n8n/issues/30199)) ([515ae7c](https://github.com/n8n-io/n8n/commit/515ae7ced4b109880306788cb16977c15de92279))
* **core:** Add MCP tool to list credentials ([#29438](https://github.com/n8n-io/n8n/issues/29438)) ([d6cc3be](https://github.com/n8n-io/n8n/commit/d6cc3bedd1c4e7a2849eb5cf2acf538fb3a8f3da))
* **core:** Add multi-config evaluations backend ([#29784](https://github.com/n8n-io/n8n/issues/29784)) ([8116e0a](https://github.com/n8n-io/n8n/commit/8116e0a4858044712e45c078e06e0a36103d141c))
* **core:** Add n8n-object-validation ESLint rule for community nodes ([#29698](https://github.com/n8n-io/n8n/issues/29698)) ([701f9a4](https://github.com/n8n-io/n8n/commit/701f9a462773c204a6dc8bd15c533f9c07cd6e08))
* **core:** Add no-template-placeholders ESLint rule for community nodes ([#29796](https://github.com/n8n-io/n8n/issues/29796)) ([c4056b2](https://github.com/n8n-io/n8n/commit/c4056b255edd4420fde6cb5e1028b61f10b2bcf7))
* **core:** Add observational memory storage foundation ([#29814](https://github.com/n8n-io/n8n/issues/29814)) ([be4ef22](https://github.com/n8n-io/n8n/commit/be4ef225336166937a8847c2f2615bfd29e40765))
* **core:** Define community packages with environment variables ([#29961](https://github.com/n8n-io/n8n/issues/29961)) ([730c3e1](https://github.com/n8n-io/n8n/commit/730c3e12a55a38cdbe9090eabef508cd56d67a9e))
* **core:** Generate service-specific OAuth2 credentials for dedicated MCP tools ([#29884](https://github.com/n8n-io/n8n/issues/29884)) ([8617067](https://github.com/n8n-io/n8n/commit/86170674b72acc16d781eafd08cd762c55a7672f))
* **core:** Server-side pagination, sorting, and filtering for encryption keys ([#29708](https://github.com/n8n-io/n8n/issues/29708)) ([9afbe13](https://github.com/n8n-io/n8n/commit/9afbe13b81f00f0ea7730541b4909e31b1080249))
* **core:** Transform MCP server configs into dedicated MCP tools ([#29493](https://github.com/n8n-io/n8n/issues/29493)) ([4dce41f](https://github.com/n8n-io/n8n/commit/4dce41f79573f864fde16df622c028134d743f03))
* **core:** Use McpManagerClient and enforce whether MCP server connections are allowed ([#29694](https://github.com/n8n-io/n8n/issues/29694)) ([8235474](https://github.com/n8n-io/n8n/commit/82354742d348850d8cb6efc6ffe490c53ff0a8a0))
* **Customer.io Trigger Node:** Add webhook request verification ([#29480](https://github.com/n8n-io/n8n/issues/29480)) ([a772016](https://github.com/n8n-io/n8n/commit/a772016e36a87d1fbbacbee59ebcd80dbe3b9150))
* **editor:** Add envFeatureFlag and copyButton property options ([#29733](https://github.com/n8n-io/n8n/issues/29733)) ([75053fe](https://github.com/n8n-io/n8n/commit/75053fec9373076abfba3db01a967f54f8274e83))
* **editor:** Cap eval concurrency slider at admin-set limit ([#29807](https://github.com/n8n-io/n8n/issues/29807)) ([6232de4](https://github.com/n8n-io/n8n/commit/6232de4d477ffa56e0082d87a5b63d1c9ef00d4c))
* **editor:** Eval run detail loading + error states (TRUST-70 follow-up) ([#29817](https://github.com/n8n-io/n8n/issues/29817)) ([6f9b99a](https://github.com/n8n-io/n8n/commit/6f9b99a3cf1207ece10a6bd6239a5005c6a10540))
* **editor:** Redesign evaluation run detail page ([#29592](https://github.com/n8n-io/n8n/issues/29592)) ([9014bae](https://github.com/n8n-io/n8n/commit/9014baea7ea952aaf782c53bce03d3a8f0ae5ddf))
* **editor:** Show locked state and permission notice on data redaction workflow settings ([#30022](https://github.com/n8n-io/n8n/issues/30022)) ([7635131](https://github.com/n8n-io/n8n/commit/7635131bd396252f51d29e7407099eafa92a304f))
* **Figma Trigger Node:** Add OAuth2 authentication support ([#30079](https://github.com/n8n-io/n8n/issues/30079)) ([e3e70d6](https://github.com/n8n-io/n8n/commit/e3e70d6068a3d543b29b1bd24682101ecb2e641f))
* **Figma Trigger Node:** Add webhook request verification ([#29262](https://github.com/n8n-io/n8n/issues/29262)) ([910822f](https://github.com/n8n-io/n8n/commit/910822fb0951f6ead55fc000e7743a8ee13e82e9))
* **Formstack Trigger Node:** Add webhook request verification ([#29495](https://github.com/n8n-io/n8n/issues/29495)) ([4e28652](https://github.com/n8n-io/n8n/commit/4e2865206c72833d9fe585ed941ecc83c1bec699))
* **GitLab Trigger Node:** Add webhook request verification ([#29260](https://github.com/n8n-io/n8n/issues/29260)) ([fbf89bd](https://github.com/n8n-io/n8n/commit/fbf89bde1164a19365fe4418405ddec7108543d9))
* **Jira Node:** Add OAuth2 (3LO) support ([#29414](https://github.com/n8n-io/n8n/issues/29414)) ([4d5bafc](https://github.com/n8n-io/n8n/commit/4d5bafc146125fa22d05cf924c5e68bc51263722))
* **MailerLite Trigger Node:** Add webhook request verification ([#29491](https://github.com/n8n-io/n8n/issues/29491)) ([12b7cc6](https://github.com/n8n-io/n8n/commit/12b7cc67395bf1991235ae0f00739d9f2803cb9c))
* **Mautic Trigger Node:** Add webhook request verification ([#29658](https://github.com/n8n-io/n8n/issues/29658)) ([eaadf19](https://github.com/n8n-io/n8n/commit/eaadf190b89f21f74bc3a25b16803576f91e9618))
* **Microsoft Outlook Node:** Add location and attendees fields to calendar events ([#29844](https://github.com/n8n-io/n8n/issues/29844)) ([2e21c5f](https://github.com/n8n-io/n8n/commit/2e21c5fcf83a2fc86659c7464b2bc6672230389f))
* **Microsoft Outlook Node:** Add support for recurring event instances ([#29802](https://github.com/n8n-io/n8n/issues/29802)) ([dab3653](https://github.com/n8n-io/n8n/commit/dab3653f8016b7f9187559658ea6ef58220df2d1))
* **Onfleet Trigger Node:** Add webhook request verification ([#29485](https://github.com/n8n-io/n8n/issues/29485)) ([133a5aa](https://github.com/n8n-io/n8n/commit/133a5aa0adae69f86f1603bd9ad85c852c0ccdf5))
* **Strava Node:** Allow custom OAuth2 scopes ([#29972](https://github.com/n8n-io/n8n/issues/29972)) ([5abcae6](https://github.com/n8n-io/n8n/commit/5abcae686cf1b64e06bbbd6f62b6871bc4feec56))
* **Taiga Trigger Node:** Add webhook request verification ([#29487](https://github.com/n8n-io/n8n/issues/29487)) ([3c97c49](https://github.com/n8n-io/n8n/commit/3c97c49d63c824c2a3b4284beecf8957c44c1c16))
* **Trello Trigger Node:** Add webhook request verification ([#29252](https://github.com/n8n-io/n8n/issues/29252)) ([8f1f42d](https://github.com/n8n-io/n8n/commit/8f1f42d18056ba51e450ba90ba3be65cbf9745aa))
* **Twilio Trigger Node:** Add webhook request verification ([#29259](https://github.com/n8n-io/n8n/issues/29259)) ([acc9643](https://github.com/n8n-io/n8n/commit/acc964381189aaacbeb584a16c0155ba6f96ffa1))
# [2.20.0](https://github.com/n8n-io/n8n/compare/n8n@2.19.0...n8n@2.20.0) (2026-05-05)
### Bug Fixes
* **ai-builder:** Add boundaries on the workflow builder remediation loops ([#29430](https://github.com/n8n-io/n8n/issues/29430)) ([2259f32](https://github.com/n8n-io/n8n/commit/2259f32de88c103b088b450bf46990ad2e939942))
* **ai-builder:** Allow skipping final ask-user question ([#29563](https://github.com/n8n-io/n8n/issues/29563)) ([661f990](https://github.com/n8n-io/n8n/commit/661f9908bce51076811c76c854f165f4c5acaccf))
* **ai-builder:** Filter LangSmith eval dataset by local file slugs ([#29507](https://github.com/n8n-io/n8n/issues/29507)) ([54d9286](https://github.com/n8n-io/n8n/commit/54d9286d922e0cad17d5c5de10a052d653c1591b))
* **ai-builder:** Handle properties with contradicting displayOptions as OR alternatives instead of AND ([#29500](https://github.com/n8n-io/n8n/issues/29500)) ([84ac811](https://github.com/n8n-io/n8n/commit/84ac8110f8d70dd653b4d40cb63259522731b0d0))
* **ai-builder:** Stop builder from adding auth to inbound trigger nodes by default ([#29648](https://github.com/n8n-io/n8n/issues/29648)) ([c28d501](https://github.com/n8n-io/n8n/commit/c28d501ba1630861fa0993d0d85f08efb635a5a4))
* Allow 5-field cron expressions with step values in polling nodes ([#29447](https://github.com/n8n-io/n8n/issues/29447)) ([d18f183](https://github.com/n8n-io/n8n/commit/d18f183b211416d5b74cfdc2e740b9c663ede134))
* **Anthropic Chat Model Node:** Add adaptive thinking mode for Claude Opus 4.7+ ([#29467](https://github.com/n8n-io/n8n/issues/29467)) ([90d875c](https://github.com/n8n-io/n8n/commit/90d875ce3e5a2a004a5a3d8f28ac4e9820b109f4))
* **Compare Datasets Node:** Preserve falsy values in mix mode except fields ([#29666](https://github.com/n8n-io/n8n/issues/29666)) ([62ddc5c](https://github.com/n8n-io/n8n/commit/62ddc5c443273559c286a1d2eb19efdca345ac9a))
* **core:** Accept placeholder() inside node credentials slot ([#29691](https://github.com/n8n-io/n8n/issues/29691)) ([dc6bd68](https://github.com/n8n-io/n8n/commit/dc6bd68de3b419fb1e23806781bbc125b621ed8a))
* **core:** Acquire expression isolate for dynamic node parameter requests ([#29671](https://github.com/n8n-io/n8n/issues/29671)) ([418f1f2](https://github.com/n8n-io/n8n/commit/418f1f2edb6abfebe1085b8c3b5c1b22530f1a5c))
* **core:** Add file path validation to localFile source ([#29464](https://github.com/n8n-io/n8n/issues/29464)) ([7277566](https://github.com/n8n-io/n8n/commit/7277566c64c36f5e43c17a2e620da2408ab1dcb7))
* **core:** Add GET handler to MCP endpoint for Streamable HTTP spec compliance ([#28787](https://github.com/n8n-io/n8n/issues/28787)) ([4ae0322](https://github.com/n8n-io/n8n/commit/4ae0322ef246348892000d0539904e56c122d204))
* **core:** Add timeout to external secrets provider refresh ([#29679](https://github.com/n8n-io/n8n/issues/29679)) ([e350429](https://github.com/n8n-io/n8n/commit/e35042999f7d477ed1da59f43ef03605763ac2bf))
* **core:** Apply credential allowed domains in declarative node requests ([#29082](https://github.com/n8n-io/n8n/issues/29082)) ([8551b1b](https://github.com/n8n-io/n8n/commit/8551b1b90ce16b31a017bd07177694ef39ad226d))
* **core:** Correct LDAP search filter construction ([#29388](https://github.com/n8n-io/n8n/issues/29388)) ([32dd743](https://github.com/n8n-io/n8n/commit/32dd7433b7ef168161e32c20939859060da9827c))
* **core:** Fix code node executions hanging when idle timer overlaps with task acceptance ([#29239](https://github.com/n8n-io/n8n/issues/29239)) ([7bd3532](https://github.com/n8n-io/n8n/commit/7bd3532f07c151568634e84f3ae24f38ab8e60e4))
* **core:** Fix MCP OAuth discovery URL construction and grant type selection ([#27283](https://github.com/n8n-io/n8n/issues/27283)) ([d92ec16](https://github.com/n8n-io/n8n/commit/d92ec168aa5f984513874e2978f73d8f2cbdc80e))
* **core:** Force saving executions when instance AI executes WFs ([#29515](https://github.com/n8n-io/n8n/issues/29515)) ([ef56501](https://github.com/n8n-io/n8n/commit/ef56501d4729b5b508a4c5e60263d10a8fc9db76))
* **core:** Gate Instance AI edits to pre-existing workflows ([#29501](https://github.com/n8n-io/n8n/issues/29501)) ([6175fd6](https://github.com/n8n-io/n8n/commit/6175fd6f7b56ead0176938657085b763c1204681))
* **core:** Generate array types for properties with multipleValues ([#29410](https://github.com/n8n-io/n8n/issues/29410)) ([fb65c61](https://github.com/n8n-io/n8n/commit/fb65c6155ee9ae5b11a2c409f35e98c206aaf164))
* **core:** Handle missing runData during execution recovery ([#29513](https://github.com/n8n-io/n8n/issues/29513)) ([8b7b4f5](https://github.com/n8n-io/n8n/commit/8b7b4f575d9d9b5b02a8ddf67aaff6b3d5279d78))
* **core:** Harden Set node workflow SDK contract ([#29568](https://github.com/n8n-io/n8n/issues/29568)) ([625ed5e](https://github.com/n8n-io/n8n/commit/625ed5e95a90f30e07e88253515713056e406f5b))
* **core:** Include stack trace in error logs for non-ApplicationError errors ([#29496](https://github.com/n8n-io/n8n/issues/29496)) ([16d1461](https://github.com/n8n-io/n8n/commit/16d1461858107697eac399039c834c7296fe8868))
* **core:** Increase default task runner grant token TTL to 30s ([#29443](https://github.com/n8n-io/n8n/issues/29443)) ([328f4b8](https://github.com/n8n-io/n8n/commit/328f4b8b964d587763bf14b1980916046878f0f0))
* **core:** Isolate expressions on chat resumption and test webhook deactivation ([#29703](https://github.com/n8n-io/n8n/issues/29703)) ([568e5a2](https://github.com/n8n-io/n8n/commit/568e5a24bf8f4e73d0b134dbac1631535bba10a7))
* **core:** Make MCP client registration cap tunable and surface a proper limit error ([#29429](https://github.com/n8n-io/n8n/issues/29429)) ([dad4231](https://github.com/n8n-io/n8n/commit/dad423155f1ee105e3ed1eab0b65a8d8bc2ee3a3))
* **core:** Make task runner grant token TTL configurable ([#29357](https://github.com/n8n-io/n8n/issues/29357)) ([3f350a8](https://github.com/n8n-io/n8n/commit/3f350a85770680895be5723803ef51453476fed2))
* **core:** Pass nodeTypesProvider to validate workflows fully at instance AI ([#29333](https://github.com/n8n-io/n8n/issues/29333)) ([388cd79](https://github.com/n8n-io/n8n/commit/388cd79908418d558fff36f938969cdc79fc60c2))
* **core:** Persist execution context before writing to db ([#28973](https://github.com/n8n-io/n8n/issues/28973)) ([c4bb5ae](https://github.com/n8n-io/n8n/commit/c4bb5ae8df8e7de4c7b919a82d3cf2f492edcc5b))
* **core:** Recreate data table backing tables on entity import ([#29454](https://github.com/n8n-io/n8n/issues/29454)) ([6bca1fa](https://github.com/n8n-io/n8n/commit/6bca1fa26f0d1a23c8c7e175dc6ae590eeb2036e))
* **core:** Reject empty webhookMethods in community lint rule ([#29474](https://github.com/n8n-io/n8n/issues/29474)) ([34d7a02](https://github.com/n8n-io/n8n/commit/34d7a02df73f233ef55fc78e3ea8167bc2b32a1f))
* **core:** Reset Redis retry counter on successful reconnect ([#29377](https://github.com/n8n-io/n8n/issues/29377)) ([7722023](https://github.com/n8n-io/n8n/commit/7722023abd8ffb2f96a7dbec0ba51e4d7454ea05))
* **core:** Respect global admin scope when listing favorites ([#29472](https://github.com/n8n-io/n8n/issues/29472)) ([d9d1e7c](https://github.com/n8n-io/n8n/commit/d9d1e7c44a1bcf074cdbec234b0d8d4ddb8d7d5e))
* **core:** Restore peer project discovery in share dropdowns ([#29537](https://github.com/n8n-io/n8n/issues/29537)) ([2a0e2fb](https://github.com/n8n-io/n8n/commit/2a0e2fb47ae1d82cd2354db8c2013ea46f24f21e))
* **core:** Round fractional time saved values before inserting into insights BIGINT column ([#29553](https://github.com/n8n-io/n8n/issues/29553)) ([74d55b9](https://github.com/n8n-io/n8n/commit/74d55b9c681273ae79fbaf39693bd3b37d83b66a))
* **core:** Show AI Builder draft workflows in workflow list ([#29670](https://github.com/n8n-io/n8n/issues/29670)) ([dc52bbd](https://github.com/n8n-io/n8n/commit/dc52bbd5329a27245a5fe2a1da45d9e8efe6a549))
* **core:** Use editor base URL for workflow and execution links ([#23630](https://github.com/n8n-io/n8n/issues/23630)) ([896461b](https://github.com/n8n-io/n8n/commit/896461bee3c356e66b282763cd31427a137ebd62))
* **core:** Validate workflow import URL requests ([#29178](https://github.com/n8n-io/n8n/issues/29178)) ([ecd0ba8](https://github.com/n8n-io/n8n/commit/ecd0ba8ebabc99055441290d543f0bd87a33df31))
* **core:** Wire EncryptionKeyProxy provider on bootstrap ([#29581](https://github.com/n8n-io/n8n/issues/29581)) ([ee7260c](https://github.com/n8n-io/n8n/commit/ee7260c4959b0dff8636606aebdac10eddd76e36))
* **DeepL Node:** Update credentials to use header-based authentication ([#24614](https://github.com/n8n-io/n8n/issues/24614)) ([b72bd19](https://github.com/n8n-io/n8n/commit/b72bd1987c33b15cd658d2a038b9763c6fb83b55))
* Drop template search tools from builder ([#29573](https://github.com/n8n-io/n8n/issues/29573)) ([9b00ccb](https://github.com/n8n-io/n8n/commit/9b00ccbfd1cfb123533397126123f5d2ad34071f))
* **editor:** Add proper bg color for hover state with color-mix() ([#29590](https://github.com/n8n-io/n8n/issues/29590)) ([6698c42](https://github.com/n8n-io/n8n/commit/6698c42e4ed4706825f5d2e3bac39641e261f153))
* **editor:** Align message box button radius with N8nButton ([#29397](https://github.com/n8n-io/n8n/issues/29397)) ([bc315d0](https://github.com/n8n-io/n8n/commit/bc315d087fd772218b2f3caa047c86493c048f27))
* **editor:** Fix OAuth2 credential showing "Needs first setup" after connecting ([#29617](https://github.com/n8n-io/n8n/issues/29617)) ([243f665](https://github.com/n8n-io/n8n/commit/243f665e60bff1c2531977c3f860aa7589a321e9))
* **editor:** Fix sub-workflow folder placement and connection loss ([#28770](https://github.com/n8n-io/n8n/issues/28770)) ([44579d6](https://github.com/n8n-io/n8n/commit/44579d6d3ae59a1f4eedf9a0b49cecb006053072))
* **editor:** Ignore paste events on read-only canvas ([#29673](https://github.com/n8n-io/n8n/issues/29673)) ([34c49b9](https://github.com/n8n-io/n8n/commit/34c49b9c238de5d5ee0b9421918435c4582eb13a))
* **editor:** Keep publish actions menu enabled for published workflows ([#29396](https://github.com/n8n-io/n8n/issues/29396)) ([c65fa28](https://github.com/n8n-io/n8n/commit/c65fa28e1caac5a49e6a5e82d3354ed631be0df4))
* **editor:** Load more executions on tall screens ([#29407](https://github.com/n8n-io/n8n/issues/29407)) ([a273a9d](https://github.com/n8n-io/n8n/commit/a273a9d3f498d8112605f1277ce7848d8bd357c3))
* **editor:** Make instance ai resource link chips open resources ([#29577](https://github.com/n8n-io/n8n/issues/29577)) ([b97ca36](https://github.com/n8n-io/n8n/commit/b97ca36a99d099288cfc127df98038b2b64c03d5))
* **editor:** Make textarea resize handle accessible in NDV ([#29676](https://github.com/n8n-io/n8n/issues/29676)) ([9fda733](https://github.com/n8n-io/n8n/commit/9fda7332c4c0a8851a7482365a967ea18db2a816))
* **editor:** Mark workflow dirty after debug pinData changes ([#28886](https://github.com/n8n-io/n8n/issues/28886)) ([2beb006](https://github.com/n8n-io/n8n/commit/2beb0062a5f92c883f18abaf9ea33590a41aca49))
* **editor:** Never block publishing on node execution issues ([#29479](https://github.com/n8n-io/n8n/issues/29479)) ([5a56459](https://github.com/n8n-io/n8n/commit/5a564591291989f13ac667eed575332f7f4d2a6a))
* **editor:** Polish encryption keys date range filter ([#29569](https://github.com/n8n-io/n8n/issues/29569)) ([56412bc](https://github.com/n8n-io/n8n/commit/56412bcce2ef1d364acdbe422f5c88762319bb22))
* **editor:** Remove clipping for focus panel textarea ([#28677](https://github.com/n8n-io/n8n/issues/28677)) ([5361257](https://github.com/n8n-io/n8n/commit/5361257a80e515e1cc26cdf10e8ceb78c9ec70be))
* **editor:** Restore read-only mode for archived workflows on canvas ([#29559](https://github.com/n8n-io/n8n/issues/29559)) ([a7ef741](https://github.com/n8n-io/n8n/commit/a7ef7416b111384d250f975e718c691b2674fef6))
* **editor:** Show permission-aware message on redacted input/output panels ([#29521](https://github.com/n8n-io/n8n/issues/29521)) ([83c400e](https://github.com/n8n-io/n8n/commit/83c400e8d47c875f57dce26680358595822ce012))
* **editor:** Surface unofficial verified community node tools in AI Tools picker ([#28985](https://github.com/n8n-io/n8n/issues/28985)) ([f77dfd1](https://github.com/n8n-io/n8n/commit/f77dfd1a11591124e6db61c72ed207067bae6214))
* Fix ollama node url path and thinking tokens ([#23963](https://github.com/n8n-io/n8n/issues/23963)) ([4ea1153](https://github.com/n8n-io/n8n/commit/4ea1153dfb903346bead9e6d328ec8f543c80559))
* **Google Drive Node:** Resolve original file name when copying with empty name ([#28896](https://github.com/n8n-io/n8n/issues/28896)) ([c274976](https://github.com/n8n-io/n8n/commit/c2749768aa5d173c3354e8d31a18c438ebd5fdfb))
* **Merge Node:** Improve SQL Query mode memory efficiency and error reporting ([#28993](https://github.com/n8n-io/n8n/issues/28993)) ([12275c8](https://github.com/n8n-io/n8n/commit/12275c86d992115fef2ded4e5f172730222c5669))
* **Microsoft Outlook Trigger Node:** Use per-folder endpoints for folder-scoped message polling ([#29663](https://github.com/n8n-io/n8n/issues/29663)) ([f401f91](https://github.com/n8n-io/n8n/commit/f401f9101d08fc62eef7e051f3baa23638c80c1b))
* No Credits state for n8n Connect badge ([#29375](https://github.com/n8n-io/n8n/issues/29375)) ([47ad397](https://github.com/n8n-io/n8n/commit/47ad39777f9525324524f2595fc4506065f33a9c))
* **Notion Node:** Support app.notion.com URL format for page and block ID extraction ([#29554](https://github.com/n8n-io/n8n/issues/29554)) ([221c7f7](https://github.com/n8n-io/n8n/commit/221c7f7410d25b89b052e89d745184675b69dc53))
* **Postgres Node:** Output Large-Format Numbers As option ignored after pool is cached ([#29477](https://github.com/n8n-io/n8n/issues/29477)) ([a65e181](https://github.com/n8n-io/n8n/commit/a65e181a2213f1b984c225539302a1a12a30cc9b))
* **Salesforce Node:** Allow overriding JWT audience with My Domain URL ([#29016](https://github.com/n8n-io/n8n/issues/29016)) ([9decb1e](https://github.com/n8n-io/n8n/commit/9decb1e2a9f6d6612014354d7ca6f8b62600ce9d))
* **Schedule Node:** Cap day-of-month jitter at 28 ([#29614](https://github.com/n8n-io/n8n/issues/29614)) ([86f47ee](https://github.com/n8n-io/n8n/commit/86f47ee6dc88397b05bfb784b0092674ba3b4289))
* Skip AI tool generation for community trigger nodes ([#29453](https://github.com/n8n-io/n8n/issues/29453)) ([c724dac](https://github.com/n8n-io/n8n/commit/c724dace38ec1e3aa69de40d48e068cf36c962b0))
* **Snowflake Node:** Avoid call stack overflow on large result sets ([#29200](https://github.com/n8n-io/n8n/issues/29200)) ([b2ac67f](https://github.com/n8n-io/n8n/commit/b2ac67f15452c625d4dee146a040b6324cdfefbb))
* **Telegram Trigger Node:** Drop pending updates when creating a new webhook ([#29103](https://github.com/n8n-io/n8n/issues/29103)) ([4358f1d](https://github.com/n8n-io/n8n/commit/4358f1d51c588e76d03aa677f9b7deabbbc1af9d))
* **Todoist Node:** Migrate to Todoist unified API v1 endpoints ([#29532](https://github.com/n8n-io/n8n/issues/29532)) ([5799481](https://github.com/n8n-io/n8n/commit/5799481d1c3bf14806d11ba2928af4f7f88db29f))
* Use explicit node references for AI memory session keys ([#29473](https://github.com/n8n-io/n8n/issues/29473)) ([139b803](https://github.com/n8n-io/n8n/commit/139b803daefca44fd66a92156867d77ccdffcc66))
* Validate sql ([#24706](https://github.com/n8n-io/n8n/issues/24706)) ([47a6658](https://github.com/n8n-io/n8n/commit/47a6658b2d4cd2d4be5e59b0d61f9bd25b553007))
* **Zammad Node:** Add To and CC fields for email articles ([#28860](https://github.com/n8n-io/n8n/issues/28860)) ([e04f027](https://github.com/n8n-io/n8n/commit/e04f027b5dd008eb0c9354d166c716a93cdc48b7))
### Features
* Add instance-level JWKS URI endpoint for JWE public key distribution ([#29498](https://github.com/n8n-io/n8n/issues/29498)) ([794334c](https://github.com/n8n-io/n8n/commit/794334cd79f1ee5a05cd0d818fc801920e0fe6d9))
* Add no-runtime-dependencies ESLint rule ([#29366](https://github.com/n8n-io/n8n/issues/29366)) ([8aace75](https://github.com/n8n-io/n8n/commit/8aace75535f53ebf37c2a547849e044948c99cb8))
* Add pairwise workflow eval pipeline ([#29123](https://github.com/n8n-io/n8n/issues/29123)) ([fdceec2](https://github.com/n8n-io/n8n/commit/fdceec21b996a1456ceb44389e760a80d75d49a1))
* Add valid-credential-references ESLint rule ([#29452](https://github.com/n8n-io/n8n/issues/29452)) ([c6c6f8f](https://github.com/n8n-io/n8n/commit/c6c6f8ff3889a48ac73d5e5bb242e88818707fc0))
* **core:** Add --include and --exclude flags to import:credentials command ([#29364](https://github.com/n8n-io/n8n/issues/29364)) ([f5132b9](https://github.com/n8n-io/n8n/commit/f5132b9e9abe23eb1a2b1225d889f1dd83d83f94))
* **core:** Add configurable event log path per process ([#29403](https://github.com/n8n-io/n8n/issues/29403)) ([45effb8](https://github.com/n8n-io/n8n/commit/45effb8959e4013d46a022a5a3f901e9d0284d35))
* **core:** Add endpoint to toggle mcp access for multiple workflows ([#29007](https://github.com/n8n-io/n8n/issues/29007)) ([0d907d6](https://github.com/n8n-io/n8n/commit/0d907d67945dfd9624eda6f3fb634cee4bd2d195))
* **core:** Add JWE decryption to OAuth2 credential flow ([#29497](https://github.com/n8n-io/n8n/issues/29497)) ([ad7cdcc](https://github.com/n8n-io/n8n/commit/ad7cdcc04f47e1c34754636098ff698b7b153d05))
* **core:** Add MCP tool search executions ([#29161](https://github.com/n8n-io/n8n/issues/29161)) ([1d9548c](https://github.com/n8n-io/n8n/commit/1d9548c81f6a984882aadd7091cd649967aa7201))
* **core:** Add migration for postgres variable values ([#29489](https://github.com/n8n-io/n8n/issues/29489)) ([898ba5a](https://github.com/n8n-io/n8n/commit/898ba5ae2562542af11031b5dfdf0400afb91fbd))
* **core:** Add preAuthentication support to requestOAuth2 pipeline ([#29418](https://github.com/n8n-io/n8n/issues/29418)) ([473d49c](https://github.com/n8n-io/n8n/commit/473d49c9b18ff4d8226f54fe0c5c8a2a1c6fdca5))
* **core:** Bootstrap legacy CBC and initial GCM encryption keys on startup ([#29400](https://github.com/n8n-io/n8n/issues/29400)) ([9576ab9](https://github.com/n8n-io/n8n/commit/9576ab907cc3bdb560d1b40a1582ecf67c253d3a))
* **core:** Broadcast workflow settings updates ([#29459](https://github.com/n8n-io/n8n/issues/29459)) ([9cb1605](https://github.com/n8n-io/n8n/commit/9cb160585c05ccb1770554cd0998ea4d9b0ab3cc))
* **core:** Decouple insights pruning max age from license ([#29527](https://github.com/n8n-io/n8n/issues/29527)) ([45c18fb](https://github.com/n8n-io/n8n/commit/45c18fb09c04749063edc3545c38ad37006c0c49))
* **core:** Fix user access control logic ([#29481](https://github.com/n8n-io/n8n/issues/29481)) ([484cb2e](https://github.com/n8n-io/n8n/commit/484cb2efba8b33555c4d34bb95680d16a3328c1e))
* **core:** Manage MCP settings via environment variables ([#29368](https://github.com/n8n-io/n8n/issues/29368)) ([05e10e2](https://github.com/n8n-io/n8n/commit/05e10e268083fd7f9f1176634f0c1cab88297b94))
* **core:** Run evaluation test cases in parallel behind PostHog rollout flag ([#29412](https://github.com/n8n-io/n8n/issues/29412)) ([4c76aa1](https://github.com/n8n-io/n8n/commit/4c76aa1467d08d5f188cf8b7716b52b410f2bd65))
* **core:** Use versioned prebuilt Daytona snapshots for Instance AI sandboxes ([#29359](https://github.com/n8n-io/n8n/issues/29359)) ([308d0b4](https://github.com/n8n-io/n8n/commit/308d0b42b32a3372bac3a759b15ee410c9d095eb))
* **core:** Warn and skip on duplicate scheduled executions ([#28649](https://github.com/n8n-io/n8n/issues/28649)) ([b8b7571](https://github.com/n8n-io/n8n/commit/b8b75719ba373a27f60c6f471b170216fe7c41a9))
* **editor:** Add data encryption keys settings page ([#29068](https://github.com/n8n-io/n8n/issues/29068)) ([656f9c2](https://github.com/n8n-io/n8n/commit/656f9c2d7fc635c117efaeb40bb0fb98256f5ba3))
* **editor:** Add environment variable to disable workflow autosave ([#25144](https://github.com/n8n-io/n8n/issues/25144)) ([a2afc47](https://github.com/n8n-io/n8n/commit/a2afc47c226a716b7ae059306e684748c9d65947))
* **editor:** Add reveal redacted data permission to custom roles execution section ([#29526](https://github.com/n8n-io/n8n/issues/29526)) ([be22095](https://github.com/n8n-io/n8n/commit/be22095646c0daf2bbdc2afb7ebc4c1e4a50e349))
* **editor:** Add transition on Sidebar collapsed ([#29650](https://github.com/n8n-io/n8n/issues/29650)) ([07b5343](https://github.com/n8n-io/n8n/commit/07b53430f9e9efefaa78d90d3a613d5518ede4e5))
* **editor:** Hide model selector for unsupported AI Gateway actions ([#29588](https://github.com/n8n-io/n8n/issues/29588)) ([0f7776e](https://github.com/n8n-io/n8n/commit/0f7776e972c1d94d0f61d6d8855865802ef2a273))
* **editor:** Move Switch component to core design system ([#27322](https://github.com/n8n-io/n8n/issues/27322)) ([758f89c](https://github.com/n8n-io/n8n/commit/758f89c9ef4b936e1904c244698ccb4d92f6dd51))
* **editor:** Track IdP role mapping in provisioning telemetry ([#29416](https://github.com/n8n-io/n8n/issues/29416)) ([40da23f](https://github.com/n8n-io/n8n/commit/40da23f68899bc11240b252d417aa01dec8485a9))
* **editor:** Update copy for mcp settings ([#29399](https://github.com/n8n-io/n8n/issues/29399)) ([5f93b48](https://github.com/n8n-io/n8n/commit/5f93b48e79067251e782940489848f81f897d3a4))
* Include updatedAt in encryption key response DTO ([#29424](https://github.com/n8n-io/n8n/issues/29424)) ([569f94b](https://github.com/n8n-io/n8n/commit/569f94bb828bdd662bb291bd1d566e4e2a8ebdae))
* **instance-ai:** Orchestrator-executed checkpoint tasks for planned workflow verification ([#29049](https://github.com/n8n-io/n8n/issues/29049)) ([ad359b5](https://github.com/n8n-io/n8n/commit/ad359b5e2ceaaf2ba04559e43117d81bc5f2df25))
* **Netlify Trigger Node:** Add webhook request verification ([#29256](https://github.com/n8n-io/n8n/issues/29256)) ([1516ec7](https://github.com/n8n-io/n8n/commit/1516ec7c06ab797dbf94fd1b8a0322209e6ee0bc))
* **Slack Node:** Allow users to configure OAuth2 scopes ([#28728](https://github.com/n8n-io/n8n/issues/28728)) ([aa0daf9](https://github.com/n8n-io/n8n/commit/aa0daf9fb630661d35e8bd006ed3b749051f7a7d))
* Validate workflow-sdk output topology against mode ([#29363](https://github.com/n8n-io/n8n/issues/29363)) ([0a80722](https://github.com/n8n-io/n8n/commit/0a80722dcb3fcdbc23d9e768413b3141ec329adc))
# [2.19.0](https://github.com/n8n-io/n8n/compare/n8n@2.18.0...n8n@2.19.0) (2026-04-28)
### Bug Fixes
* Add credential auth and test for Twilio, Pipedrive, Asana, Freshdesk, Workable ([#28265](https://github.com/n8n-io/n8n/issues/28265)) ([a2aa69d](https://github.com/n8n-io/n8n/commit/a2aa69dbd7c931a869417d28c26297fe5beb86e9))
* Additional keys in routing nodes ([#28758](https://github.com/n8n-io/n8n/issues/28758)) ([8e49800](https://github.com/n8n-io/n8n/commit/8e49800421e6611084c1d092cd2aad82696d3e22))
* **ai-builder:** Adjust chat trigger memory builderHints ([#29156](https://github.com/n8n-io/n8n/issues/29156)) ([b6fcabc](https://github.com/n8n-io/n8n/commit/b6fcabc0252c9a021892dd940796f7282a45971c))
* **ai-builder:** Hide and reap intermediate AI-created workflows ([#29066](https://github.com/n8n-io/n8n/issues/29066)) ([632ae67](https://github.com/n8n-io/n8n/commit/632ae67de3fa33487e1ad513043cf740cb32bb1a))
* **ai-builder:** Improve button, icon, callout and workflowSelector schemas ([#28828](https://github.com/n8n-io/n8n/issues/28828)) ([afe4298](https://github.com/n8n-io/n8n/commit/afe4298427c4e4f6cc0ebf11dc5a3b7a41f38f10))
* **ai-builder:** Keep workflow identity across rebuild/patch ([#28926](https://github.com/n8n-io/n8n/issues/28926)) ([13029e6](https://github.com/n8n-io/n8n/commit/13029e6d039ac61280543406b88e1b680fe22c55))
* **ai-builder:** Prevent duplicate workflow creation on parallel submits in instance AI ([#28793](https://github.com/n8n-io/n8n/issues/28793)) ([782b2d1](https://github.com/n8n-io/n8n/commit/782b2d18b22601199919b7674100dd88aaa8f7ac))
* **ai-builder:** Stop treating empty defaults as satisfying required for the Split node ([#28978](https://github.com/n8n-io/n8n/issues/28978)) ([8b33424](https://github.com/n8n-io/n8n/commit/8b33424d0f222a605d38b736e6e4a65682bad4e3))
* **ai-builder:** Support 'disabledOptions' in node schemas ([#28894](https://github.com/n8n-io/n8n/issues/28894)) ([bc5e490](https://github.com/n8n-io/n8n/commit/bc5e490f686d908fc4a1efdbb4b2198bdbc98993))
* **ai-builder:** Validate merge node connections matches 'numberInputs' parameter ([#28831](https://github.com/n8n-io/n8n/issues/28831)) ([0e838de](https://github.com/n8n-io/n8n/commit/0e838deab27f3f81908e17486d94c604f8ba4fc4))
* **ai-builder:** Validate required inputs on AI nodes ([#29159](https://github.com/n8n-io/n8n/issues/29159)) ([97bdbd0](https://github.com/n8n-io/n8n/commit/97bdbd055a5a89ab2c73a4933ac413f429724832))
* Allow task runner to invoke skills via slash command prefix ([#29302](https://github.com/n8n-io/n8n/issues/29302)) ([65e55a8](https://github.com/n8n-io/n8n/commit/65e55a88c14a7d1d29a927c62d18d293f701e51d))
* **Brevo Node:** Send valid email attachments with correct filenames ([#28816](https://github.com/n8n-io/n8n/issues/28816)) ([7d6f777](https://github.com/n8n-io/n8n/commit/7d6f7778080a488da49b5935bbbb56dd30105724))
* **core:** Fixes user search functionality in ProjectSettings for pr… ([#28914](https://github.com/n8n-io/n8n/issues/28914)) ([1eea626](https://github.com/n8n-io/n8n/commit/1eea62629acb62d3ab3683b0049c15be11901039))
* **core:** Add missing break statements in filter condition evaluation ([#27708](https://github.com/n8n-io/n8n/issues/27708)) ([1e77f71](https://github.com/n8n-io/n8n/commit/1e77f7146dc63106cd9e486811a0292eba07632e))
* **core:** Allow .trim() in workflow-sdk parsing and coerce stringified patches ([#29111](https://github.com/n8n-io/n8n/issues/29111)) ([b44e9d1](https://github.com/n8n-io/n8n/commit/b44e9d12070eb8db614be8cde51216c94d3c63fe))
* **core:** Allow SAML connection test without saving config first ([#28702](https://github.com/n8n-io/n8n/issues/28702)) ([828d0ee](https://github.com/n8n-io/n8n/commit/828d0ee9069372ac921f975d66a101bb70d0133a))
* **core:** Broadcast MCP availability change via push connection ([#29019](https://github.com/n8n-io/n8n/issues/29019)) ([e183ae4](https://github.com/n8n-io/n8n/commit/e183ae4434a9ec6aee57792846d5483a754cdb56))
* **core:** Can't install community nodes on Windows ([#28481](https://github.com/n8n-io/n8n/issues/28481)) ([7e3a2f6](https://github.com/n8n-io/n8n/commit/7e3a2f6885eb11e5eab10a70985a9adc0900f5fa))
* **core:** Clean up project mapping rules on provisioning strategy switch ([#28726](https://github.com/n8n-io/n8n/issues/28726)) ([c662862](https://github.com/n8n-io/n8n/commit/c662862d7f4c929176d7f3b7a53332b5359b8adb))
* **core:** Declare credentialType on MCP workflow-builder autoAssignedCredentials schema ([#28353](https://github.com/n8n-io/n8n/issues/28353)) ([41424b3](https://github.com/n8n-io/n8n/commit/41424b3e9986da328f1a420e7d46c2d7a7ac3701))
* **core:** Fix fixedCollection validation issues and empty setup cards on instance AI ([#28794](https://github.com/n8n-io/n8n/issues/28794)) ([8630845](https://github.com/n8n-io/n8n/commit/8630845cbd288b5b83201c62b3b6c4fef010546e))
* **core:** Fix health endpoint cross-origin requests ([#28878](https://github.com/n8n-io/n8n/issues/28878)) ([b6eabb4](https://github.com/n8n-io/n8n/commit/b6eabb4ce5030df2e9d477e27fd5dbdf9d940a1c))
* **core:** Fix publishing dynamic credential chathub flow ([#28827](https://github.com/n8n-io/n8n/issues/28827)) ([852d082](https://github.com/n8n-io/n8n/commit/852d0825d7ead81c5e276f482dd383c040730083))
* **core:** Generate title once there's enough user context ([#28721](https://github.com/n8n-io/n8n/issues/28721)) ([2d624a5](https://github.com/n8n-io/n8n/commit/2d624a521e4c86c4d1ff5d7c1a151549db0707d7))
* **core:** Guard event log parsing against unbounded memory growth ([#28594](https://github.com/n8n-io/n8n/issues/28594)) ([a817cbc](https://github.com/n8n-io/n8n/commit/a817cbc1c03fcd184cd11613819ac0415355adb5))
* **core:** Harden event log parse against malformed input ([#29004](https://github.com/n8n-io/n8n/issues/29004)) ([b2b1370](https://github.com/n8n-io/n8n/commit/b2b1370e5d70a02771f315630a0477f2038a259d))
* **core:** Hide pre-resolved setup requests from Instance AI wizard ([#28731](https://github.com/n8n-io/n8n/issues/28731)) ([9ea2ef1](https://github.com/n8n-io/n8n/commit/9ea2ef1840d5fb49369c32e9b28d109845d852bd))
* **core:** Improve error messages for invalid node and trigger input ([#28053](https://github.com/n8n-io/n8n/issues/28053)) ([0f4c5b3](https://github.com/n8n-io/n8n/commit/0f4c5b396d21e2477099c8436259b143faf5ca90))
* **core:** Link existing email users on LDAP sync instead of failing ([#28695](https://github.com/n8n-io/n8n/issues/28695)) ([767b3ab](https://github.com/n8n-io/n8n/commit/767b3abea1bfc1f44277a353d5f9267e4b43f37f))
* **core:** Pass userId through webhook test execution path for redaction ([#28775](https://github.com/n8n-io/n8n/issues/28775)) ([19b2388](https://github.com/n8n-io/n8n/commit/19b2388acad90df462613366728632863b6e378a))
* **core:** Persist execution metadata for failed executions in scaling mode ([#28774](https://github.com/n8n-io/n8n/issues/28774)) ([1256da9](https://github.com/n8n-io/n8n/commit/1256da91f0f61bd0fb799b47bd190168f82ada20))
* **core:** Pin Alpine version in Docker builder stages for reproducible builds ([#29097](https://github.com/n8n-io/n8n/issues/29097)) ([147bd8c](https://github.com/n8n-io/n8n/commit/147bd8c84f05e801217f566a2e6c9f784aeead2f))
* **core:** Pin sandbox workflow-sdk to host version ([#29048](https://github.com/n8n-io/n8n/issues/29048)) ([9ea8533](https://github.com/n8n-io/n8n/commit/9ea8533873928e7240e343189f872465bc68569f))
* **core:** Preserve manual scopes for inherited generic OAuth2 credentials ([#27858](https://github.com/n8n-io/n8n/issues/27858)) ([5ee534c](https://github.com/n8n-io/n8n/commit/5ee534c3b8490d74ad2d9c0b52d30952da8f0d87))
* **core:** Preserve user-selected credentials when AI recreates a node ([#28943](https://github.com/n8n-io/n8n/issues/28943)) ([5fa1f8f](https://github.com/n8n-io/n8n/commit/5fa1f8f7d90c8f0f7fbf0003a9e76ceb06bb6def))
* **core:** Prevent Redis connection recovery from being missed ([#28256](https://github.com/n8n-io/n8n/issues/28256)) ([494a855](https://github.com/n8n-io/n8n/commit/494a855d34905750b057b98f3e4eb0c8bcdee317))
* **core:** Prevent S3 socket pool exhaustion on partial stream reads ([#28313](https://github.com/n8n-io/n8n/issues/28313)) ([481fbdf](https://github.com/n8n-io/n8n/commit/481fbdf186dc8b166c164592c82ec9b7a5edb8b0))
* **core:** Request helper function support setting agentOptions ([#28756](https://github.com/n8n-io/n8n/issues/28756)) ([4ce186a](https://github.com/n8n-io/n8n/commit/4ce186a14dd3b6f6f268afadaa48be8b07227eaa))
* **core:** Scope live and test webhook handlers to their route family ([#28804](https://github.com/n8n-io/n8n/issues/28804)) ([bb25d4c](https://github.com/n8n-io/n8n/commit/bb25d4cc388a08fe90b7f504fc67edb4f667404d))
* **core:** Shift existing rules on create to avoid order conflict ([#28722](https://github.com/n8n-io/n8n/issues/28722)) ([c55b95f](https://github.com/n8n-io/n8n/commit/c55b95ff0626fe9b73d0e5d45230531777fe7015))
* **core:** Support mixed bracket/dot notation in external secrets expressions ([#28711](https://github.com/n8n-io/n8n/issues/28711)) ([a757ddd](https://github.com/n8n-io/n8n/commit/a757ddd4a86f8700b7ee290d659b320018d7417a))
* **core:** Surface credential and resource choice when more than one match exists ([#29087](https://github.com/n8n-io/n8n/issues/29087)) ([0d16dd5](https://github.com/n8n-io/n8n/commit/0d16dd5dfb6511db0292b67d450c34efcde55efb))
* **core:** Surface pagination state in instance AI credentials list ([#29098](https://github.com/n8n-io/n8n/issues/29098)) ([9345d13](https://github.com/n8n-io/n8n/commit/9345d132fa240528b3ea0f078e55264092308776))
* **core:** Upgrade task-runner-launcher to v1.4.5 ([#29155](https://github.com/n8n-io/n8n/issues/29155)) ([b37044e](https://github.com/n8n-io/n8n/commit/b37044e12441e89a80052dc14f22a78792eb9948))
* **core:** Use upsert for MCP OAuth consent to allow re-authorization ([#28703](https://github.com/n8n-io/n8n/issues/28703)) ([26ecadc](https://github.com/n8n-io/n8n/commit/26ecadcf94bf8e49cd168f22ed72b5e6ed99d8dd))
* **core:** Workflow import cli doesn't deregister crons for deactivated workflows ([#29129](https://github.com/n8n-io/n8n/issues/29129)) ([553976d](https://github.com/n8n-io/n8n/commit/553976d065ff3e82c41cb0e89e9ccfbe947a80c7))
* Correct typo in proxy error message: not value -> not valid ([#28318](https://github.com/n8n-io/n8n/issues/28318)) ([b143830](https://github.com/n8n-io/n8n/commit/b143830f24e4079d829735b222bdcd4f15e2319a))
* Correctly rename all temporal binary files after execution ([#28960](https://github.com/n8n-io/n8n/issues/28960)) ([71b2b88](https://github.com/n8n-io/n8n/commit/71b2b88eb8b6420dc3fa8e73234e0f82f8d7822a))
* Disable "Get 100 free OpenAI API credits"  if aiGateway enabled in the license ([#29050](https://github.com/n8n-io/n8n/issues/29050)) ([67bd8de](https://github.com/n8n-io/n8n/commit/67bd8de90fe127e93874b794c1525214ce89c704))
* Disable until we encrypt ([#28875](https://github.com/n8n-io/n8n/issues/28875)) ([1b02a0d](https://github.com/n8n-io/n8n/commit/1b02a0dbf49256ef740de58f23d87dad114d4d6b))
* **Discord Node:** Correctly handle API rate limits ([#29051](https://github.com/n8n-io/n8n/issues/29051)) ([089d6bd](https://github.com/n8n-io/n8n/commit/089d6bda0e32ee6509ae9ee6840af67356407bb1))
* **Discord Node:** Fix file name and mimetype for file upload ([#28807](https://github.com/n8n-io/n8n/issues/28807)) ([d3ef7e3](https://github.com/n8n-io/n8n/commit/d3ef7e3e0fb885adfe83cef8ad4f803592601a29))
* E2E test for token exchange ([#28895](https://github.com/n8n-io/n8n/issues/28895)) ([d49049d](https://github.com/n8n-io/n8n/commit/d49049dd3f868be2710f6ba433bd3d610b4b93de))
* **EditImage Node:** Fix orientation when modifying images ([#28970](https://github.com/n8n-io/n8n/issues/28970)) ([b649eea](https://github.com/n8n-io/n8n/commit/b649eea01d411335852b2fe14ccd3cee489d382d))
* **editor:** Align Model and Sandbox visibility with edit permissions ([#29076](https://github.com/n8n-io/n8n/issues/29076)) ([e10509f](https://github.com/n8n-io/n8n/commit/e10509f11420d9745473e9110bdea9ea509f7009))
* **editor:** Allow `name` parameters to be defined by AI ([#28763](https://github.com/n8n-io/n8n/issues/28763)) ([76358a6](https://github.com/n8n-io/n8n/commit/76358a60bee8a1f1c1a151521eaa1db65adf4547))
* **editor:** Allow users to logout of dynamic creds in chathub ([#29117](https://github.com/n8n-io/n8n/issues/29117)) ([b1ddbf2](https://github.com/n8n-io/n8n/commit/b1ddbf26b05b85b4f4445955d8abc95fd00a2711))
* **editor:** Checklist not showing workflow settings configuration ([#28034](https://github.com/n8n-io/n8n/issues/28034)) ([3c54cda](https://github.com/n8n-io/n8n/commit/3c54cda57577e617413e48190cec88777b305469))
* **editor:** Constrain InstanceAiView stacking context below sidebar ([#29324](https://github.com/n8n-io/n8n/issues/29324)) ([b71a31d](https://github.com/n8n-io/n8n/commit/b71a31d2a9f4b44fc4736a2e6a768a99e6da2b5a))
* **editor:** Copy to editor not using pinned data from the execution ([#28905](https://github.com/n8n-io/n8n/issues/28905)) ([20d9215](https://github.com/n8n-io/n8n/commit/20d9215736b707a728bc7cb1a234a585ef985bf4))
* **editor:** Disable WF version menu only when all actions are unavailable ([#29266](https://github.com/n8n-io/n8n/issues/29266)) ([23170e4](https://github.com/n8n-io/n8n/commit/23170e436ad00e96ad64f09000317bd4720bb0a4))
* **editor:** Fix column collapse button not visible in table view ([#28899](https://github.com/n8n-io/n8n/issues/28899)) ([0eb30c6](https://github.com/n8n-io/n8n/commit/0eb30c6ca741dfe73d5254002c3467a65c36e50f))
* **editor:** HTTP request node showing warning about credentials not set when they are set ([#28270](https://github.com/n8n-io/n8n/issues/28270)) ([4869e0a](https://github.com/n8n-io/n8n/commit/4869e0a4638d94117b402f2ce177be0084744679))
* **editor:** Move tooltip for required RMC fields to the right ([#28803](https://github.com/n8n-io/n8n/issues/28803)) ([713c498](https://github.com/n8n-io/n8n/commit/713c4981b7b88ceb2f8512c20ee5c18914a16ce1))
* **editor:** Populate chat history in executions view ([#29229](https://github.com/n8n-io/n8n/issues/29229)) ([cf5cdbf](https://github.com/n8n-io/n8n/commit/cf5cdbfbcf3245a5120b6f71fb8cc5de35091ea4))
* **editor:** Prevent executions table flicker on empty auto-refresh ([#28805](https://github.com/n8n-io/n8n/issues/28805)) ([2bd8b47](https://github.com/n8n-io/n8n/commit/2bd8b472072aa853b1a87857890f6cd8343927c8))
* **editor:** Refresh wallet balance when usage refresh is clicked ([#29067](https://github.com/n8n-io/n8n/issues/29067)) ([7fd0b37](https://github.com/n8n-io/n8n/commit/7fd0b3761da5913d78c00907a143246d19f8c2b8))
* **editor:** Restore missing node icons for HTTP-auth credentials ([#28814](https://github.com/n8n-io/n8n/issues/28814)) ([345ce7f](https://github.com/n8n-io/n8n/commit/345ce7f0dc8850151005291171388b4afc63a358))
* **editor:** Save button never shows saved state after saving credentials ([#28486](https://github.com/n8n-io/n8n/issues/28486)) ([4352749](https://github.com/n8n-io/n8n/commit/4352749ec9e5cfcf19258c555fd80db1a9d4df1a))
* **editor:** Show error toasts in Instance AI executable canvas ([#29328](https://github.com/n8n-io/n8n/issues/29328)) ([dc33223](https://github.com/n8n-io/n8n/commit/dc33223d3becdb30b59ff66d93eaea6dcec314d4))
* **editor:** Show Manage community-node link to admins, not just owners ([#29060](https://github.com/n8n-io/n8n/issues/29060)) ([ef944b4](https://github.com/n8n-io/n8n/commit/ef944b4a52a19f82b3ab5db4a581967510d5b2d0))
* **editor:** Show saved credentials when node has mismatched credentials object ([#28693](https://github.com/n8n-io/n8n/issues/28693)) ([d8f742b](https://github.com/n8n-io/n8n/commit/d8f742baa686f85b51042ce7e50f962e67f71574))
* **editor:** Surface configured minimum password length in UI ([#28194](https://github.com/n8n-io/n8n/issues/28194)) ([330211c](https://github.com/n8n-io/n8n/commit/330211c5ae914dfe013d6996a706b4ec79f81536))
* **Embeddings Google Gemini Node:** Update wrong default embeddings model ([#26977](https://github.com/n8n-io/n8n/issues/26977)) ([a1d733b](https://github.com/n8n-io/n8n/commit/a1d733bb9a0fb722c9fbd439a22b003c2cd5a43e))
* Fix 11 security issues in @xmldom/xmldom, defu, @langchain/community and 5 more ([#29126](https://github.com/n8n-io/n8n/issues/29126)) ([35449aa](https://github.com/n8n-io/n8n/commit/35449aaa7b1ca016c919e555f9ba86ee0ea1db8f))
* Fix 15 critical issues in protobufjs, defu, @langchain/community and 6 more ([#28661](https://github.com/n8n-io/n8n/issues/28661)) ([6650068](https://github.com/n8n-io/n8n/commit/6650068f00ec220db5f779fd02f686413a10f264))
* Fixes AI Assistant opt-in modal terms link ([#28779](https://github.com/n8n-io/n8n/issues/28779)) ([10f619f](https://github.com/n8n-io/n8n/commit/10f619f6d610c180ca19743852167863ae9a7a6e))
* **GitHub Node:** Return pagination token as string in resource locators ([#29099](https://github.com/n8n-io/n8n/issues/29099)) ([5dda3b2](https://github.com/n8n-io/n8n/commit/5dda3b2142b752722efb6ef4691ca74b618ae33d))
* **Gmail Trigger Node:** Add maxResults limit to prevent OOM on large inboxes ([#28470](https://github.com/n8n-io/n8n/issues/28470)) ([b9c4618](https://github.com/n8n-io/n8n/commit/b9c4618270c04cb6b3f491310999713439260a6b))
* **Gmail Trigger Node:** Exclude scheduled emails from trigger query ([#29244](https://github.com/n8n-io/n8n/issues/29244)) ([58d7983](https://github.com/n8n-io/n8n/commit/58d79832bc3933557a89eae0e2c62da67c10cd64))
* **Google Gemini Node:** Filter out undefined parts when processing API responses ([#28567](https://github.com/n8n-io/n8n/issues/28567)) ([0aabee0](https://github.com/n8n-io/n8n/commit/0aabee0a99f3e7eaf7a0232f8b76732889730043))
* **Google Gemini Node:** Show Number of Images option only for models that supports it ([#29153](https://github.com/n8n-io/n8n/issues/29153)) ([b0ec5cd](https://github.com/n8n-io/n8n/commit/b0ec5cdb69b91bc563c219009aa36864c6746820))
* **Jenkins Node:** Properly load job parameters ([#28631](https://github.com/n8n-io/n8n/issues/28631)) ([f2aa016](https://github.com/n8n-io/n8n/commit/f2aa0160af7b51c99a17125e64f3cfd636cf59fb))
* **MCP Server Trigger Node:** Only return error name and message in tool error responses ([#28791](https://github.com/n8n-io/n8n/issues/28791)) ([6db02fe](https://github.com/n8n-io/n8n/commit/6db02fe9283211e5aac89b757aadf3e0a8a0bd33))
* **Microsoft Outlook Trigger Node:** Show nested subfolders in folder dropdowns ([#28759](https://github.com/n8n-io/n8n/issues/28759)) ([3409a67](https://github.com/n8n-io/n8n/commit/3409a67dfec527a55b79282a784ebf7d955f96da))
* **MongoDB Chat Memory Node:** Add connection pool limit ([#28042](https://github.com/n8n-io/n8n/issues/28042)) ([a88ee76](https://github.com/n8n-io/n8n/commit/a88ee76553ed5e1798f2689ff79602c59e2c36bb))
* **Moonshot Kimi Node:** Update default model to kimi-k2.6 ([#28859](https://github.com/n8n-io/n8n/issues/28859)) ([1c52b0a](https://github.com/n8n-io/n8n/commit/1c52b0a448f9afd6bdd9eca91b0ba83515afc200))
* **MySql Node:** Fix table name filtering ([#28911](https://github.com/n8n-io/n8n/issues/28911)) ([ccbd914](https://github.com/n8n-io/n8n/commit/ccbd91459425713d870bfe03919defd98b366215))
* Preserve `structuredContent` in MCP nodes to prevent AI Agent reasoning loops ([#27297](https://github.com/n8n-io/n8n/issues/27297)) ([048e01e](https://github.com/n8n-io/n8n/commit/048e01e0606482f33948db49578d8b2f926d4f92))
* **RabbitMQ Trigger Node:** Redeliver messages on failed executions ([#28712](https://github.com/n8n-io/n8n/issues/28712)) ([7be9f65](https://github.com/n8n-io/n8n/commit/7be9f653998b34f51e0a3bda91c7a5dcbe0f3750))
* **Schedule Node:** Avoid using 0 day of month ([#28432](https://github.com/n8n-io/n8n/issues/28432)) ([a9e5f0e](https://github.com/n8n-io/n8n/commit/a9e5f0ea482603582298e60af7cd466b1ee3e8bb))
* Update hono, protobufjs, yaml, and other dependencies ([#28877](https://github.com/n8n-io/n8n/issues/28877)) ([c4ff018](https://github.com/n8n-io/n8n/commit/c4ff0188dbca498356a4bca7ac941bc82a09affc))
* Use different runtime for each agent call, refactor state management ([#27915](https://github.com/n8n-io/n8n/issues/27915)) ([68c289f](https://github.com/n8n-io/n8n/commit/68c289f76fa0be253355a9532cb96ac924f2f1fa))
* **WooCommerce Trigger Node:** Guard HMAC verification against missing secret ([#28964](https://github.com/n8n-io/n8n/issues/28964)) ([5cef662](https://github.com/n8n-io/n8n/commit/5cef66269e5101d209fb49b6ce1ee78af24426fe))
* **Xero Node:** Update OAuth Scopes to meet new Xero API requirements ([#27563](https://github.com/n8n-io/n8n/issues/27563)) ([7f54ff4](https://github.com/n8n-io/n8n/commit/7f54ff4acf73940afc6a59df851177d2c7b1cafe))
### Features
* Add warning when publishing workflow, if some nodes in it are using ai gateway credentials ([#29089](https://github.com/n8n-io/n8n/issues/29089)) ([d2d7dfc](https://github.com/n8n-io/n8n/commit/d2d7dfc276c92015d1bae0ed352bb4661e7697c4))
* **Alibaba Cloud Node:** Switch to dynamic model list fetched from API ([#28839](https://github.com/n8n-io/n8n/issues/28839)) ([3a165d4](https://github.com/n8n-io/n8n/commit/3a165d4843e254267f7177d0c1d88758e044c546))
* **API:** Add encryption key management endpoints ([#28897](https://github.com/n8n-io/n8n/issues/28897)) ([5af4e1c](https://github.com/n8n-io/n8n/commit/5af4e1cc191ad956b5af7f081e2bcee08a2d8ebf))
* **AwsS3 Node:** Add option to return common prefixes in bucket search ([#28571](https://github.com/n8n-io/n8n/issues/28571)) ([13dbcf9](https://github.com/n8n-io/n8n/commit/13dbcf9bbb8db9070415a39225bddc5c57b8a4b7))
* **core:** Accept token-exchanged scoped JWTs on the instance MCP server ([#28909](https://github.com/n8n-io/n8n/issues/28909)) ([1d325a2](https://github.com/n8n-io/n8n/commit/1d325a20ca8a67eb2539df30de278bcce11c3de6))
* **core:** Add --projectId filter to export:workflow and export:credentials commands ([#29329](https://github.com/n8n-io/n8n/issues/29329)) ([2d721d2](https://github.com/n8n-io/n8n/commit/2d721d29f3c4d2c33cc8c661e069f75f6a54b96c))
* **core:** Add AES-256-GCM cipher support ([#28916](https://github.com/n8n-io/n8n/issues/28916)) ([0c02111](https://github.com/n8n-io/n8n/commit/0c021116bc61d4aa9ccf2fe0f05cdd4668888e92))
* **core:** Add audit logs for webhook waiting and resuming ([#28204](https://github.com/n8n-io/n8n/issues/28204)) ([bb6a5e4](https://github.com/n8n-io/n8n/commit/bb6a5e47b08e17fc5f4e704e2c6dead6476ea60c))
* **core:** Add delete folder endpoint to public API ([#28984](https://github.com/n8n-io/n8n/issues/28984)) ([f931b17](https://github.com/n8n-io/n8n/commit/f931b17a93a4e1e247f51d04ac84b2a6382b0bc8))
* **core:** Add encryptWithKey and decryptWithKey to Cipher service ([#28608](https://github.com/n8n-io/n8n/issues/28608)) ([c40599b](https://github.com/n8n-io/n8n/commit/c40599b82ef7935242f21691ce5f2c9e8986f248))
* **core:** Add instance setting to disable public chat in Chat Trigger ([#27565](https://github.com/n8n-io/n8n/issues/27565)) ([af3841f](https://github.com/n8n-io/n8n/commit/af3841f629a33d018677e518e3d9a3d7cd491c5f))
* **core:** Add observability for the VM expression engine ([#28715](https://github.com/n8n-io/n8n/issues/28715)) ([f3efcf8](https://github.com/n8n-io/n8n/commit/f3efcf8a5478aa7f76db85802b4d3e6fafc5be74))
* **core:** Add opt-in RFC-style outbound User-Agent via env flag ([#28771](https://github.com/n8n-io/n8n/issues/28771)) ([67af2e1](https://github.com/n8n-io/n8n/commit/67af2e177d7b398e910a0b25e22c7b993e537af0))
* **core:** Add PATCH endpoint for data table column management ([#29090](https://github.com/n8n-io/n8n/issues/29090)) ([b437371](https://github.com/n8n-io/n8n/commit/b4373715f3e4b6e15ec228a8e6983ca628393d8f))
* **core:** Add public API endpoints for data table column management… ([#29073](https://github.com/n8n-io/n8n/issues/29073)) ([2b0add1](https://github.com/n8n-io/n8n/commit/2b0add185f509209a27a6c7981d844545d2aa81f))
* **core:** Add public API endpoints for folder management ([#28760](https://github.com/n8n-io/n8n/issues/28760)) ([ff9d7d6](https://github.com/n8n-io/n8n/commit/ff9d7d67561b4d668c0eeefbd9e3eb13de1610e5))
* **core:** Add public API endpoints for folder management (folderId) ([#28790](https://github.com/n8n-io/n8n/issues/28790)) ([fda3d5c](https://github.com/n8n-io/n8n/commit/fda3d5cf8d8d166ef6dd1511d905f4963f15a85d))
* **core:** Bootstrap encryption key set from environment ([#28716](https://github.com/n8n-io/n8n/issues/28716)) ([c012b52](https://github.com/n8n-io/n8n/commit/c012b52ac23a16fa70e103656cf571f6c30e0219))
* **core:** Broadcast workflow updates from MCP tools to open editors ([#28709](https://github.com/n8n-io/n8n/issues/28709)) ([b1ca129](https://github.com/n8n-io/n8n/commit/b1ca12949676dbcb5092c09f3a3db7270c9f9eb7))
* **core:** Centralise user listing permissions for internal and publ… ([#28989](https://github.com/n8n-io/n8n/issues/28989)) ([9e694f5](https://github.com/n8n-io/n8n/commit/9e694f5f4191a756b1dc4c46f3f417732e115e27))
* **core:** Drop BetaTag from sidebar, use 'Preview' instead for new features ([#29347](https://github.com/n8n-io/n8n/issues/29347)) ([a7d7352](https://github.com/n8n-io/n8n/commit/a7d7352c9be2903476cf7ef1ae5fdc65df5eb1be))
* **core:** Guard Instance AI prompts against asking for plaintext secrets ([#28876](https://github.com/n8n-io/n8n/issues/28876)) ([d58e67e](https://github.com/n8n-io/n8n/commit/d58e67e76eda48aacb1e981cd50b99c5f56367cf))
* **core:** Make SSO connection settings configurable via env vars ([#28714](https://github.com/n8n-io/n8n/issues/28714)) ([3bd7a28](https://github.com/n8n-io/n8n/commit/3bd7a2847c0fdc3c2709ad21e3a91a5116ac7949))
* **core:** OTEL changes to support context propagation ([#28720](https://github.com/n8n-io/n8n/issues/28720)) ([9599fb9](https://github.com/n8n-io/n8n/commit/9599fb9d5416e1c4aae43679484d717a789c165e))
* **core:** Remove expression role mapping feature flag ([#29361](https://github.com/n8n-io/n8n/issues/29361)) ([a70a314](https://github.com/n8n-io/n8n/commit/a70a31411d2f42351ea61212721aa9064e0e6391))
* **core:** Scale expression isolate pool to 0 after inactivity ([#28472](https://github.com/n8n-io/n8n/issues/28472)) ([10dbf32](https://github.com/n8n-io/n8n/commit/10dbf32596b63ceb489ff14787a95cca97b63d62))
* **core:** Stamp x-n8n-feature on proxied LLM calls for cost attribution ([#28987](https://github.com/n8n-io/n8n/issues/28987)) ([e129518](https://github.com/n8n-io/n8n/commit/e1295187f187d8bebf9338a5e07e4a34c8b92c68))
* **core:** Wire Cipher to encryption key proxy for key rotation support ([#29013](https://github.com/n8n-io/n8n/issues/29013)) ([641d492](https://github.com/n8n-io/n8n/commit/641d492d56781d05740af652f09a64538b6a8259))
* **editor:** Add Delete permanently link to workflow archive toast ([#29157](https://github.com/n8n-io/n8n/issues/29157)) ([98ec56a](https://github.com/n8n-io/n8n/commit/98ec56ad77dfd4bbba1ecbbc8a06554a80448ea9))
* **editor:** Move computer use toggle to chat sidebar ([#28974](https://github.com/n8n-io/n8n/issues/28974)) ([47bb91e](https://github.com/n8n-io/n8n/commit/47bb91e9b4ade6638e8d54fb79cae54b90b0a1a2))
* **editor:** Track favorite toggle events ([#28810](https://github.com/n8n-io/n8n/issues/28810)) ([86a6d1b](https://github.com/n8n-io/n8n/commit/86a6d1b1fafc8deb8a7611b4bc0fd2d807ed090b))
* **editor:** Warn when data table cell value exceeds safe integer range ([#28904](https://github.com/n8n-io/n8n/issues/28904)) ([e62e44f](https://github.com/n8n-io/n8n/commit/e62e44f3f8c42547a1c8726ed8d9a50ca5a069d6))
* Enable log streamin settings via env vars ([#29005](https://github.com/n8n-io/n8n/issues/29005)) ([ff6d65e](https://github.com/n8n-io/n8n/commit/ff6d65e22aa758ee78f4f27ac0c781e3754bd917))
* **Google Drive Node:** Add Markdown export option for Google Docs download ([#27006](https://github.com/n8n-io/n8n/issues/27006)) ([80cb82e](https://github.com/n8n-io/n8n/commit/80cb82e9c52e6170b75dc0841ee9b143058bdd5e))
* **Google Gemini Node:** Gemini default models update ([#28853](https://github.com/n8n-io/n8n/issues/28853)) ([46739a5](https://github.com/n8n-io/n8n/commit/46739a5bc464af81ebf5145d2ae37fd3bfbb5fa8))
* In the n8n Connect table on row click open execution related to that usage row ([#29075](https://github.com/n8n-io/n8n/issues/29075)) ([f658278](https://github.com/n8n-io/n8n/commit/f6582783ea80cc99b58265f11563f03088f7f217))
* **MiniMax Node:** Add standalone MiniMax vendor node ([#28748](https://github.com/n8n-io/n8n/issues/28748)) ([0295369](https://github.com/n8n-io/n8n/commit/02953693a61ba0856fe53c1e29a6d0b8829404a0))
* **OpenAI Node:** Use dynamic model selection for image edit and update analyze model filter ([#29223](https://github.com/n8n-io/n8n/issues/29223)) ([5f2c32a](https://github.com/n8n-io/n8n/commit/5f2c32ad6edea90df0feca2d1d87c6ed6860ef36))
* **Postgres Node:** Sort PostgreSQL schemas and tables alphabetically when fetching ([#28036](https://github.com/n8n-io/n8n/issues/28036)) ([11ebf61](https://github.com/n8n-io/n8n/commit/11ebf6147111c87a2d47a5dcb87d2a0873ef60fc))
* **Salesforce Node:** Add middle name, suffix, and identity fields to contacts ([#23905](https://github.com/n8n-io/n8n/issues/23905)) ([c7a0f3e](https://github.com/n8n-io/n8n/commit/c7a0f3eb3956da1d74f6becaa927ed3dfe4c6e21))
* **Slack Node:** Add emoji reaction filter to Slack Trigger ([#28628](https://github.com/n8n-io/n8n/issues/28628)) ([90843cf](https://github.com/n8n-io/n8n/commit/90843cf4bae9d27087801a56f30fce67dc89e420))
# [2.18.0](https://github.com/n8n-io/n8n/compare/n8n@2.17.0...n8n@2.18.0) (2026-04-21)
### Bug Fixes
* **ai-builder:** Increase orchestrator max steps from default 5 to 60 ([#28429](https://github.com/n8n-io/n8n/issues/28429)) ([3c850f2](https://github.com/n8n-io/n8n/commit/3c850f2711d53ded62a3540c67b9ec02143cbb3f))
* **ai-builder:** Scope artifacts panel to resources produced in-thread ([#28678](https://github.com/n8n-io/n8n/issues/28678)) ([7b3696f](https://github.com/n8n-io/n8n/commit/7b3696f3f7d95ab3cbaeb8ca58fdc74264a83b52))
* **ai-builder:** Use placeholders for user-provided values instead of hardcoding fake addresses ([#28407](https://github.com/n8n-io/n8n/issues/28407)) ([39c6217](https://github.com/n8n-io/n8n/commit/39c62171092618149fa67ccb9a384a5a3aadd4e8))
* **Alibaba Cloud Chat Model Node:** Add credential-level url field for AI gateway compatibility ([#28697](https://github.com/n8n-io/n8n/issues/28697)) ([dd6c28c](https://github.com/n8n-io/n8n/commit/dd6c28c6d16274354b83d3cc6a731f2f7a859a14))
* **ClickUp Node:** Unclear error message when using OAuth credentials ([#28584](https://github.com/n8n-io/n8n/issues/28584)) ([19aadf1](https://github.com/n8n-io/n8n/commit/19aadf19f753d64cc2cd80af3c5b3dd957a4ede7))
* **core:** Add required field validation to MCP OAuth client registration ([#28490](https://github.com/n8n-io/n8n/issues/28490)) ([8716316](https://github.com/n8n-io/n8n/commit/87163163e67001f69a2a2d7b4a650e0511614d62))
* **core:** Cascade-cancel dependent planned tasks when a parent task fails ([#28656](https://github.com/n8n-io/n8n/issues/28656)) ([35f9bed](https://github.com/n8n-io/n8n/commit/35f9bed4de39350717192d9f272ad044ad50b323))
* **core:** Enforce credential access checks in dynamic node parameter requests ([#28446](https://github.com/n8n-io/n8n/issues/28446)) ([ac41112](https://github.com/n8n-io/n8n/commit/ac411127314921aaf82b7b97d76eeaa2703b708c))
* **core:** Ensure single zod instance across workspace packages ([#28604](https://github.com/n8n-io/n8n/issues/28604)) ([107c48f](https://github.com/n8n-io/n8n/commit/107c48f65c10d26f8f01d1bee5d2eb77b9d26084))
* **core:** Filter stale credentials from setup wizard requests ([#28478](https://github.com/n8n-io/n8n/issues/28478)) ([657bdf1](https://github.com/n8n-io/n8n/commit/657bdf136fd0fc01cee3629baf65e130ee80840a))
* **core:** Fix public API package update process ([#28475](https://github.com/n8n-io/n8n/issues/28475)) ([34430ae](https://github.com/n8n-io/n8n/commit/34430aedb15fa5305be475582e04f08967415e38))
* **core:** Fix workflow-sdk validation for plain workflow objects ([#28416](https://github.com/n8n-io/n8n/issues/28416)) ([62dc073](https://github.com/n8n-io/n8n/commit/62dc073b3d954dc885359962c02ae8aa84d17c43))
* **core:** Guard against undefined config properties in credential overwrites ([#28573](https://github.com/n8n-io/n8n/issues/28573)) ([77d27bc](https://github.com/n8n-io/n8n/commit/77d27bc826e4e91c2c589a62cbb6b997cacccd16))
* **core:** Handle git fetch failure during source control startup ([#28422](https://github.com/n8n-io/n8n/issues/28422)) ([fa3299d](https://github.com/n8n-io/n8n/commit/fa3299d0425dfa2eaeaca6732dc46e0181e6fd68))
* **core:** Handle invalid percent sequences and equals signs in HTTP response headers ([#27691](https://github.com/n8n-io/n8n/issues/27691)) ([ca71d89](https://github.com/n8n-io/n8n/commit/ca71d89d885d01f8663e29a2a5b1f06c713aede8))
* **core:** Implement data tables name collision detection on pull ([#26416](https://github.com/n8n-io/n8n/issues/26416)) ([e5aaeb5](https://github.com/n8n-io/n8n/commit/e5aaeb53a93c63a04978e2a6eb7aa7255fcf510b))
* **core:** Prevent nodes tool crash on flattened required fields ([#28670](https://github.com/n8n-io/n8n/issues/28670)) ([3e72430](https://github.com/n8n-io/n8n/commit/3e724303c537739319e91f8bcaf7070fe105ffc7))
* **core:** Resolve additional keys lazily in VM expression engine ([#28430](https://github.com/n8n-io/n8n/issues/28430)) ([98b833a](https://github.com/n8n-io/n8n/commit/98b833a07d6d0f705633d7cb48298ee953688bd1))
* **core:** Skip disabled Azure Key Vault secrets and handle partial fetch failures ([#28325](https://github.com/n8n-io/n8n/issues/28325)) ([6217d08](https://github.com/n8n-io/n8n/commit/6217d08ce9b53d6fd5277fa0708ed13d36e0e934))
* **core:** Skip npm outdated check for verified-only community packages ([#28335](https://github.com/n8n-io/n8n/issues/28335)) ([2959b4d](https://github.com/n8n-io/n8n/commit/2959b4dc2a6cfd3733cc83bd6442dddd4cff08d2))
* Disable axios built-in proxy for OAuth2 token requests ([#28513](https://github.com/n8n-io/n8n/issues/28513)) ([56f36a6](https://github.com/n8n-io/n8n/commit/56f36a6d1961d95780fb8258e8876d7d512503c2))
* **editor:** Advance wizard step on Continue instead of applying setup ([#28698](https://github.com/n8n-io/n8n/issues/28698)) ([3b15e47](https://github.com/n8n-io/n8n/commit/3b15e470b54b13e9fe68e81c81a757c06b264783))
* **editor:** Center sub-node icons and refresh triggers panel icons ([#28515](https://github.com/n8n-io/n8n/issues/28515)) ([6739856](https://github.com/n8n-io/n8n/commit/6739856aa32689b43d143ae4909e1f3d85dc4106))
* **editor:** Display placeholder sentinels as hint text in setup wizard ([#28482](https://github.com/n8n-io/n8n/issues/28482)) ([bb7d137](https://github.com/n8n-io/n8n/commit/bb7d137cf735bcdf65bbcf8ff58fa911d83121f5))
* **editor:** Gate Instance AI input while setup wizard is open ([#28685](https://github.com/n8n-io/n8n/issues/28685)) ([db83a95](https://github.com/n8n-io/n8n/commit/db83a95522957c10a3466f0b57944c8b8827347a))
* **editor:** Hide setup parameter issue icons until user interacts with input ([#28010](https://github.com/n8n-io/n8n/issues/28010)) ([00b0558](https://github.com/n8n-io/n8n/commit/00b0558c2b1ed6bc4d47a86cb1bfca8eb55a47bc))
* **editor:** Improve disabled Google sign-in button styling and tooltip alignment ([#28536](https://github.com/n8n-io/n8n/issues/28536)) ([e848230](https://github.com/n8n-io/n8n/commit/e8482309478eed05793dcaa4d82185936439663f))
* **editor:** Improve setup wizard placeholder detection and card completion scoping ([#28474](https://github.com/n8n-io/n8n/issues/28474)) ([d172113](https://github.com/n8n-io/n8n/commit/d17211342e4ee8c8ec89a9c918017884e2de0763))
* **editor:** Only show role assignment warning modal when value actually changed ([#28387](https://github.com/n8n-io/n8n/issues/28387)) ([9c97931](https://github.com/n8n-io/n8n/commit/9c97931ca06d407bec1c6a8bab510d206afba394))
* **editor:** Prevent setup wizard disappearing on requestId-driven remount ([#28473](https://github.com/n8n-io/n8n/issues/28473)) ([04d57c5](https://github.com/n8n-io/n8n/commit/04d57c5fd62a5b9a2e086a3f540b7f50a932b62d))
* **editor:** Re-initialize SSO store after login to populate OIDC redirect URL ([#28386](https://github.com/n8n-io/n8n/issues/28386)) ([21317b8](https://github.com/n8n-io/n8n/commit/21317b8945dec9169e36b7e5fdf867713018661d))
* **editor:** Refine resource dependency badge ([#28087](https://github.com/n8n-io/n8n/issues/28087)) ([f216fda](https://github.com/n8n-io/n8n/commit/f216fda511062a40199b986351693677ebb2919e))
* **editor:** Reset OIDC form dirty state after saving IdP settings ([#28388](https://github.com/n8n-io/n8n/issues/28388)) ([1042350](https://github.com/n8n-io/n8n/commit/1042350f4e0f6ed44b51a1d707de665f71437faa))
* **editor:** Reset remote values on credentials change ([#26282](https://github.com/n8n-io/n8n/issues/26282)) ([5e11197](https://github.com/n8n-io/n8n/commit/5e111975d4086c060ac3d29d07da7c00ea2103a1))
* **editor:** Resolve nodes stuck on loading after execution in instance-ai preview ([#28450](https://github.com/n8n-io/n8n/issues/28450)) ([c97c3b4](https://github.com/n8n-io/n8n/commit/c97c3b4d12e166091be9ea1de969a17d64c36ec2))
* **editor:** Restore WASM file paths for cURL import in HTTP Request node ([#28610](https://github.com/n8n-io/n8n/issues/28610)) ([51bc71e](https://github.com/n8n-io/n8n/commit/51bc71e897e2baaf729963bf0f373a73505aee43))
* **editor:** Show auth type selector in Instance AI workflow setup ([#28707](https://github.com/n8n-io/n8n/issues/28707)) ([1b13d32](https://github.com/n8n-io/n8n/commit/1b13d325f12a5a27d139c75164114ee41583a902))
* **editor:** Show relevant node in workflow activation errors ([#26691](https://github.com/n8n-io/n8n/issues/26691)) ([c9cab11](https://github.com/n8n-io/n8n/commit/c9cab112f99a5da2742012773450bf7721484c28))
* **Google Cloud Firestore Node:** Fix empty array serialization in jsonToDocument ([#28213](https://github.com/n8n-io/n8n/issues/28213)) ([7094395](https://github.com/n8n-io/n8n/commit/7094395cef8e71f767df6fa5e242cf2fa42366ed))
* **Google Drive Node:** Continue on error support for download file operation ([#28276](https://github.com/n8n-io/n8n/issues/28276)) ([30128c9](https://github.com/n8n-io/n8n/commit/30128c9254be2214e746e0158296c1f1bd8ab4d8))
* **Google Gemini Node:** Determine the file extention from MIME type for image and video operations ([#28616](https://github.com/n8n-io/n8n/issues/28616)) ([73659cb](https://github.com/n8n-io/n8n/commit/73659cb3e7eccd48a739829be0a4d7a6557ce4a1))
* **GraphQL Node:** Improve error response handling ([#28209](https://github.com/n8n-io/n8n/issues/28209)) ([357fb72](https://github.com/n8n-io/n8n/commit/357fb7210ab201e13e2d3256a7886cf382656f22))
* **HubSpot Node:** Rename HubSpot "App Token" auth to "Service Key" ([#28479](https://github.com/n8n-io/n8n/issues/28479)) ([8c3e692](https://github.com/n8n-io/n8n/commit/8c3e6921741f0e28ba28f8fb39797d5e19db71c9))
* **HubSpot Trigger Node:** Add missing property selectors ([#28595](https://github.com/n8n-io/n8n/issues/28595)) ([d179f66](https://github.com/n8n-io/n8n/commit/d179f667c0044fd246d8e8535cd3a741d3f96b6f))
* **IMAP Node:** Fix out-of-memory crash after ECONNRESET on reconnect ([#28290](https://github.com/n8n-io/n8n/issues/28290)) ([2d0b231](https://github.com/n8n-io/n8n/commit/2d0b231e31f265f39dd95d6794bd74d9b5592056))
* Link to n8n website broken in n8n forms ([#28627](https://github.com/n8n-io/n8n/issues/28627)) ([ff950e5](https://github.com/n8n-io/n8n/commit/ff950e5840214c515d413b45f174d9638a51dd39))
* **LinkedIn Node:** Update LinkedIn API version in request headers ([#28564](https://github.com/n8n-io/n8n/issues/28564)) ([25e07ca](https://github.com/n8n-io/n8n/commit/25e07cab5a66b04960753055131d355e0323d971))
* **OpenAI Node:** Replace hardcoded models with RLC ([#28226](https://github.com/n8n-io/n8n/issues/28226)) ([4070930](https://github.com/n8n-io/n8n/commit/4070930e4c080c634df9b241175941c48afed9dc))
* **Schedule Node:** Use elapsed-time check to self-heal after missed triggers ([#28423](https://github.com/n8n-io/n8n/issues/28423)) ([5f8ab01](https://github.com/n8n-io/n8n/commit/5f8ab01f9bb26f4d27f6f882fe1024f27caf4d67))
* Update working memory using tools ([#28467](https://github.com/n8n-io/n8n/issues/28467)) ([39189c3](https://github.com/n8n-io/n8n/commit/39189c39859fbb4c1562a03ae3e6cd29195f7d1d))
### Features
* Add deployment_key table, entity, repository, and migration ([#28329](https://github.com/n8n-io/n8n/issues/28329)) ([59edd6a](https://github.com/n8n-io/n8n/commit/59edd6ae5421aa6be34ee009a3024e0ca9843467))
* Add Prometheus counters for token exchange ([#28453](https://github.com/n8n-io/n8n/issues/28453)) ([c6534fa](https://github.com/n8n-io/n8n/commit/c6534fa0b389a394e7591d3fc5ec565409279004))
* AI Gateway credentials endpoint instance url ([#28520](https://github.com/n8n-io/n8n/issues/28520)) ([d012346](https://github.com/n8n-io/n8n/commit/d012346c777455de5bde9cab218f0c4f2d712fa0))
* **API:** Add missing credential endpoints (GET by ID and test) ([#28519](https://github.com/n8n-io/n8n/issues/28519)) ([9a65549](https://github.com/n8n-io/n8n/commit/9a65549575bb201c3f55888d71e04663f622eb5b))
* **core:** Add `require-node-description-fields` ESLint rule for icon and subtitle ([#28400](https://github.com/n8n-io/n8n/issues/28400)) ([5504099](https://github.com/n8n-io/n8n/commit/550409923a3d8d6961648674024eabb0d0749cfc))
* **core:** Add KeyManagerService for encryption key lifecycle management ([#28533](https://github.com/n8n-io/n8n/issues/28533)) ([9dd3e59](https://github.com/n8n-io/n8n/commit/9dd3e59acb6eb94bb38ffe01677ea1c9a108d87b))
* **core:** Configure OIDC settings via env vars ([#28185](https://github.com/n8n-io/n8n/issues/28185)) ([36261fb](https://github.com/n8n-io/n8n/commit/36261fbe7ad55a7b3bcc19809b6decb401b245bb))
* **core:** Persist deployment_key entries for stability across restarts and key rotation ([#28518](https://github.com/n8n-io/n8n/issues/28518)) ([bb96d2e](https://github.com/n8n-io/n8n/commit/bb96d2e50a6b7cd77ea6256bb1446e8b3b348bd2))
* **core:** Support npm dist-tags in community node installation ([#28067](https://github.com/n8n-io/n8n/issues/28067)) ([ca871cc](https://github.com/n8n-io/n8n/commit/ca871cc10aca97de8c0892e0735c9fa2ed16d251))
* **core:** Support npm registry token authentication to install private community node packages ([#28228](https://github.com/n8n-io/n8n/issues/28228)) ([8b105cc](https://github.com/n8n-io/n8n/commit/8b105cc0cf6e84e069f6b7f3a98c334cd44876c1))
* **core:** Track workflow action source for external API and MCP requests ([#28483](https://github.com/n8n-io/n8n/issues/28483)) ([575c34e](https://github.com/n8n-io/n8n/commit/575c34eae1bdf8e9d5d5fe7d31c92f57f27fcc27))
* **core:** Workflow tracing - add workflow version id ([#28424](https://github.com/n8n-io/n8n/issues/28424)) ([9a22fe5](https://github.com/n8n-io/n8n/commit/9a22fe5a255b20be7d0e78fff7e03bf79e50a62f))
* **editor:** Add favoriting for projects, folders, workflows and data tables ([#26228](https://github.com/n8n-io/n8n/issues/26228)) ([b1a075f](https://github.com/n8n-io/n8n/commit/b1a075f7609045620563f86df0e15d27b1176d45))
* **editor:** Enable workflow execution from instance AI preview canvas ([#28412](https://github.com/n8n-io/n8n/issues/28412)) ([5b376cb](https://github.com/n8n-io/n8n/commit/5b376cb12d6331e4e458a1f1880fcddce76d1db9))
* Enable security policy settings via env vars ([#28321](https://github.com/n8n-io/n8n/issues/28321)) ([1108467](https://github.com/n8n-io/n8n/commit/1108467f44bf987c0f5a5a0eafb6396e2745b8ce))
* **Linear Trigger Node:** Add signing secret validation ([#28522](https://github.com/n8n-io/n8n/issues/28522)) ([3b248ee](https://github.com/n8n-io/n8n/commit/3b248eedc289c62f32f16da677c75b25df0fcb9f))
* **MiniMax Chat Model Node:** Add MiniMax Chat Model sub-node ([#28305](https://github.com/n8n-io/n8n/issues/28305)) ([bd927d9](https://github.com/n8n-io/n8n/commit/bd927d93503a65e0be18c4c40e68dcad96f68d82))
* **Slack Node:** Add app_home_opened as a dedicated trigger event ([#28626](https://github.com/n8n-io/n8n/issues/28626)) ([f1dab3e](https://github.com/n8n-io/n8n/commit/f1dab3e29530ee596d68db474024ddbae5fa055a))
### Reverts
* Make Wait node fully durable by removing in-memory execution path ([#28538](https://github.com/n8n-io/n8n/issues/28538)) ([bb9bec3](https://github.com/n8n-io/n8n/commit/bb9bec3ba419d46450122411839f20cd614db920))
# [2.17.0](https://github.com/n8n-io/n8n/compare/n8n@2.16.0...n8n@2.17.0) (2026-04-13)

View File

@ -55,7 +55,7 @@ The most important directories:
workflows. **Contact n8n before
starting on any changes here**
- [/packages/frontend/@n8n/design-system](/packages/frontend/@n8n/design-system) - Vue frontend components
- [/packages/frontend/editor-ui](/packages/editor-ui) - Vue frontend workflow editor
- [/packages/frontend/editor-ui](/packages/frontend/editor-ui) - Vue frontend workflow editor
- [/packages/node-dev](/packages/node-dev) - CLI to create new n8n-nodes
- [/packages/nodes-base](/packages/nodes-base) - Base n8n nodes
- [/packages/workflow](/packages/workflow) - Workflow code with interfaces which

View File

@ -16,7 +16,8 @@
"**/CHANGELOG.md",
"**/cl100k_base.json",
"**/o200k_base.json",
"**/*.generated.ts"
"**/*.generated.ts",
"**/expectations/**"
]
},
"formatter": {

View File

@ -43,7 +43,7 @@ reviews:
## Step 4: Design System Style Rules
Follow `.agents/design-system-style-rules.md` for all CSS/SCSS/Vue style
Follow `.claude/plugins/n8n/skills/design-system-rules/SKILL.md` for all CSS/SCSS/Vue style
review guidance.
Enforcement level:
@ -213,7 +213,7 @@ reviews:
humans handle edge cases.
- name: Design System Tokens
description: |-
Follow `.agents/design-system-style-rules.md`.
Follow `.claude/plugins/n8n/skills/design-system-rules/SKILL.md`.
Apply balanced enforcement:
- Strong warning: hard-coded visual values, legacy token usage, and

View File

@ -0,0 +1,20 @@
ARG NODE_VERSION=24.14.1
FROM node:${NODE_VERSION}-alpine3.22
ENV NODE_ENV=production
RUN apk add --no-cache tini
WORKDIR /app
# `compiled/` is produced by `pnpm build:docker`. It's a `pnpm deploy --prod`
# output containing package.json, dist/, and a node_modules with only
# production dependencies — no devDeps, no workspace bloat.
COPY --chown=node:node ./compiled /app
USER node
EXPOSE 3000
ENTRYPOINT ["tini", "--"]
CMD ["node", "dist/serve.js"]

View File

@ -3,7 +3,7 @@ ARG N8N_VERSION=snapshot
# Rebuild native addons for the container platform. The base image has no
# package manager or build tools, so we compile in a throwaway builder stage.
FROM node:${NODE_VERSION}-alpine AS builder
FROM node:${NODE_VERSION}-alpine3.22 AS builder
COPY ./compiled /usr/local/lib/node_modules/n8n
RUN apk add --no-cache python3 make g++ && \
cd /usr/local/lib/node_modules/n8n && \

View File

@ -4,7 +4,7 @@ ARG PYTHON_VERSION=3.13
# ==============================================================================
# STAGE 1: JavaScript runner (@n8n/task-runner) artifact from CI
# ==============================================================================
FROM node:${NODE_VERSION}-alpine AS javascript-runner-builder
FROM node:${NODE_VERSION}-alpine3.22 AS javascript-runner-builder
COPY ./dist/task-runner-javascript /app/task-runner-javascript
WORKDIR /app/task-runner-javascript
@ -88,7 +88,7 @@ RUN uv pip install . && rm -rf /app/task-runner-python/src
# ==============================================================================
FROM alpine:3.22 AS launcher-downloader
ARG TARGETPLATFORM
ARG LAUNCHER_VERSION=1.4.3
ARG LAUNCHER_VERSION=1.4.5
RUN set -e; \
case "$TARGETPLATFORM" in \
@ -108,7 +108,7 @@ RUN set -e; \
# ==============================================================================
# STAGE 4: Node alpine base for JS task runner
# ==============================================================================
FROM node:${NODE_VERSION}-alpine AS node-alpine
FROM node:${NODE_VERSION}-alpine3.22 AS node-alpine
# ==============================================================================
# STAGE 5: Runtime

View File

@ -106,7 +106,7 @@ RUN uv pip install . && rm -rf /app/task-runner-python/src
# ==============================================================================
FROM debian:bookworm-slim AS launcher-downloader
ARG TARGETPLATFORM
ARG LAUNCHER_VERSION=1.4.3
ARG LAUNCHER_VERSION=1.4.5
RUN set -e; \
apt-get update && apt-get install -y --no-install-recommends wget ca-certificates && \

View File

@ -49,6 +49,8 @@ const config = {
// This resolve the path mappings from the tsconfig relative to each jest.config.js
moduleNameMapper: {
'^@n8n/utils$': resolve(__dirname, 'packages/@n8n/utils/dist/index.cjs'),
// jest-resolve@29 doesn't honor `./lib/*` subpath patterns in @anthropic-ai/sdk's exports map
'^@anthropic-ai/sdk/lib/(.*)$': '@anthropic-ai/sdk/lib/$1.js',
...(compilerOptions?.paths
? pathsToModuleNameMapper(compilerOptions.paths, {
prefix: `<rootDir>${compilerOptions.baseUrl ? `/${compilerOptions.baseUrl.replace(/^\.\//, '')}` : ''}`,

View File

@ -1,6 +1,6 @@
{
"name": "n8n-monorepo",
"version": "2.17.0",
"version": "2.21.0",
"private": true,
"engines": {
"node": ">=22.16",
@ -21,7 +21,7 @@
"typecheck": "turbo typecheck",
"dev": "turbo run dev --parallel --env-mode=loose --filter=!@n8n/design-system --filter=!@n8n/chat --filter=!@n8n/task-runner",
"dev:be": "turbo run dev --parallel --env-mode=loose --filter=!@n8n/design-system --filter=!@n8n/chat --filter=!@n8n/task-runner --filter=!n8n-editor-ui",
"dev:ai": "turbo run dev --parallel --env-mode=loose --filter=@n8n/nodes-langchain --filter=n8n --filter=n8n-core",
"dev:ai": "turbo run dev --parallel --env-mode=loose --filter=@n8n/n8n-nodes-langchain --filter=n8n --filter=n8n-core",
"dev:fe": "run-p start \"dev:fe:editor --filter=@n8n/design-system\"",
"dev:fe:editor": "turbo run dev --parallel --env-mode=loose --filter=n8n-editor-ui",
"dev:e2e": "pnpm --filter=n8n-playwright dev --ui",
@ -34,6 +34,7 @@
"lint:styles:fix": "turbo run lint:styles:fix",
"lint:affected": "turbo run lint --affected",
"lint:fix": "turbo run lint:fix",
"lint:ci": "turbo run lint lint:styles",
"optimize-svg": "find ./packages -name '*.svg' ! -name 'pipedrive.svg' -print0 | xargs -0 -P16 -L20 npx svgo",
"generate:third-party-licenses": "node scripts/generate-third-party-licenses.mjs",
"setup-backend-module": "node scripts/ensure-zx.mjs && zx scripts/backend-module/setup.mjs",
@ -72,7 +73,7 @@
"jest-mock-extended": "^3.0.4",
"lefthook": "^1.7.15",
"license-checker": "^25.0.1",
"nock": "^14.0.1",
"nock": "^14.0.14",
"nodemon": "^3.0.1",
"npm-run-all2": "^7.0.2",
"p-limit": "^3.1.0",
@ -102,7 +103,6 @@
"@mistralai/mistralai": "^1.10.0",
"@n8n/typeorm>@sentry/node": "catalog:sentry",
"@types/node": "^20.17.50",
"axios": "1.13.5",
"chokidar": "4.0.3",
"esbuild": "^0.25.0",
"expr-eval@2.0.2": "npm:expr-eval-fork@3.0.0",
@ -118,8 +118,6 @@
"gaxios": ">=7.1.1",
"google-gax": "^4.3.7",
"ws": ">=8.17.1",
"brace-expansion@1": "1.1.12",
"brace-expansion@2": "2.0.3",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
"form-data": "4.0.4",
@ -138,34 +136,42 @@
"@smithy/config-resolver": ">=4.4.0",
"@rudderstack/rudder-sdk-node@<=3.0.0": "3.0.0",
"diff": "8.0.3",
"undici@5": "^6.24.0",
"undici@6": "^6.24.0",
"undici@7": "^7.24.0",
"tar": "^7.5.11",
"hono": "4.12.7",
"ajv@6": "6.14.0",
"ajv@7": "8.18.0",
"ajv@8": "8.18.0",
"bn.js@4": "5.2.3",
"bn.js@5": "5.2.3",
"langsmith": ">=0.4.6",
"lodash": "4.18.1",
"lodash-es": "4.18.1",
"@xmldom/xmldom": "0.8.12",
"word-wrap@<=1.2.4": "1.2.4",
"minimatch@<=5.1.8": "5.1.8",
"minimatch@10": "10.2.3",
"@hono/node-server": "1.19.10",
"@hono/node-server": "1.19.13",
"protobufjs": "7.5.5",
"follow-redirects": "1.16.0",
"express-rate-limit": "8.2.2",
"underscore": "1.13.8",
"fast-xml-parser": "5.5.7",
"flatted": "3.4.2",
"handlebars": "4.7.9",
"path-to-regexp": "8.4.0",
"path-to-regexp@<0.1.13": "0.1.13",
"picomatch@2": "2.3.2",
"picomatch@4": "4.0.4",
"brace-expansion@5": "5.0.5",
"avsc": "5.7.9"
"avsc": "5.7.9",
"brace-expansion@<=2.1.0": "2.1.0",
"@xmldom/xmldom": "0.8.13",
"langsmith": "0.5.19",
"yaml@<=2.8.3": "2.8.3",
"axios": "1.16.0",
"fast-xml-parser": "5.7.2",
"hono": "4.12.18",
"@anthropic-ai/sdk@<=0.91.1": "0.91.1",
"uuid@<=13.0.1": "13.0.1",
"fast-uri": "3.1.2"
},
"patchedDependencies": {
"bull@4.16.4": "patches/bull@4.16.4.patch",

View File

@ -70,8 +70,7 @@ docs/
```
The **`index.ts`** surface also exports `Workspace` / sandbox / filesystem types,
`SqliteMemory` / `PostgresMemory`, `LangSmithTelemetry`, and `evals` alongside the
core SDK builders.
`InMemoryMemory`, `LangSmithTelemetry`, and `evals` alongside the core SDK builders.
Optional **peer dependencies** (telemetry): `langsmith`, `@opentelemetry/sdk-trace-node`,
`@opentelemetry/sdk-trace-base`, `@opentelemetry/exporter-trace-otlp-http` — all

View File

@ -367,10 +367,11 @@ At end of turn, `saveToMemory()` uses `list.turnDelta()` and
`saveMessagesToThread`. If **semantic recall** is configured with an embedder
and `memory.saveEmbeddings`, new messages are embedded and stored.
**Working memory:** when configured, the runtime parses `<working_memory>`
`</working_memory>` regions from assistant text, validates structured JSON if a
schema exists, strips the tags from the visible message, and asynchronously
persists via `memory.saveWorkingMemory`.
**Working memory:** when configured, the runtime injects an `update_working_memory`
tool into the agent's tool set. The current state is included in the system prompt
so the model can read it; when new information should be persisted the model calls
the tool, which validates the input and asynchronously persists via
`memory.saveWorkingMemory`.
**Thread titles:** `titleGeneration` triggers `generateThreadTitle` (fire-and-forget)
after a successful save when persistence and memory are present.
@ -414,7 +415,7 @@ src/
tool-adapter.ts — buildToolMap, executeTool, toAiSdkTools, suspend / agent-result guards
stream.ts — convertChunk, toTokenUsage
runtime-helpers.ts — normalizeInput, usage merge, stream error helpers, …
working-memory.ts — instruction text, parse/filter for working_memory tags
working-memory.ts — instruction text, update_working_memory tool builder
strip-orphaned-tool-messages.ts
title-generation.ts
logger.ts

Some files were not shown because too many files have changed in this diff Show More