v0.11.0
Changed
-
Breaking: a compiled
.tsnode now identifies itself on line 1, not on
its last line. Open a bundled node in n8n and you used to see
var __n8n_node = {}followed by a few hundred lines of inlined helpers,
with the only trace of where it came from —// @ts-n8n sha256:…— at the
bottom, where nobody looks, naming n8n rather than the tool that put it
there. Push now writes one self-describing line where the editor opens:// n8n-decanter · workflows/orders/code/normalize-lines.ts · do not edit here · @ts-n8n sha256:39af5ea6… · v0.10.1 ca3c201 2026-08-20T09:14ZNothing you already pushed has to change. The old trailing form is read
forever and counts as fully in sync —push,diffandpreflightsay
nothing about it, and no write is queued just to relocate a marker. Nodes
adopt line 1 on their next real code push; there is no migration and no mass
re-push. The break runs the other way: an older n8n-decanter will not
recognise a node pushed by this version (its reader only looks at the last
line) and would pull such a node down as a plain.jsfile. Pre-1.0, that is
accepted rather than shimmed — upgrade the CLI everywhere that pulls the same
instance. The@ts-n8ntoken itself is unchanged, so onegrep -r @ts-n8n
still finds both forms. -
The layout guard now rejects a marker line in a node source file in either
position, and in.tsfiles too (it was trailing-only and.js-only).
That line is written bypush; it is never source. Surfaces as before via
preflight'slayoutcheck.
Fixed
-
An auth failure no longer sends you in a circle, and throttling is no
longer called an expiry. Every failed OAuth token refresh used to print
the same sentence —MCP session expired … re-run: n8n-decanter init— and
both halves of it could be wrong.initreuses.decanter-auth.json
whenever the host matches and never re-mints, so following the advice
re-probed with the same dead credentials and finished with "credentials
written anyway"; the only apparent way out was deleting a credential file
that was often perfectly fine. The three cases are now told apart:- the refresh token really is spent (
invalid_grant) — named as such,
and pointed atinit --reauth, a command that actually re-mints; - n8n is rate-limiting (429) — now retried with the same backoff the
MCP endpoint has always had (honouringRetry-After, five attempts), and
if it still fails it says the credentials are fine and never mentions
init. OAuth discovery got the same retry; both sat on barefetchcalls; - anything else — the reason is named without a diagnosis, and nothing
is suggested for discarding.
- the refresh token really is spent (
-
init's closing connection check acts on a spent token instead of
shrugging. It had the failure in hand and printed "credentials written
anyway". On a terminal it now offers to re-authorize on the spot; off one it
namesinit --reauth. Deliberately narrow — a network error, a 401, or a
403 "MCP access is disabled" still report as before, because none of them
says anything about your credentials. -
A successful first OAuth consent no longer warns "no MCP credentials
yet". The check looked for a pre-existing auth file, so a browser
authorization that had just succeeded still ended with advice to re-run
initwith a token. -
<verb> --helpprints help instead of running the verb.--helpwas
only recognised in argument slot 0, and every--flagis stripped before
dispatch, son8n-decanter init --helpwas indistinguishable from a bare
init— a request for help scaffolded a sync dir into whatever directory
it was asked from.--help(and-h) now wins from any position, before any
verb, any namespace and the picker. It prints that verb's own block rather
than the whole listing, with only the notes that apply to it;help <verb>is
the same question, and a barehelp/--helpstill prints everything.
Added
-
initrefuses to scaffold on top of a sync dir that already exists below
the target. Run from the root of a bigger repo whose sync dir lives in
n8n/,initused to drop a seconddecanter.config.json, the template,
workflows/,shared/,tsconfig.jsonand the agent configs into the root.
It now looks a few levels down first and stops, naming the sync dir it found
and the--dir=/N8N_DECANTER_DIRform that addresses it from where you are
— the same advice every read verb already gives. A terminal gets it as a
question (yscaffolds anyway); a piped or flag-driven run exits 1 having
written nothing, not even the target directory. Re-runninginitinside
an existing sync dir is unchanged. -
The provenance line carries the build stamp, not just the hash: the
node's source path relative to the sync dir, "do not edit here", the CLI
version, the git commit and the push time. The commit is HEAD at build time
and renders asca3c201+dirtywhen the sync dir has uncommitted changes —
which, withcommitOnPushon, is the normal case and reads correctly as
"built from working-tree state on top ofca3c201". Fields that cannot be
known (no git repo, unreadablepackage.json) are simply left out. None of
it is hashed, so a rename, a new commit or a CLI upgrade never makes a node
look changed — only the code below line 1 does. -
Credentials now resolve in a git worktree. Both
.envand
.decanter-auth.jsonare gitignored, so a fresh linked worktree had neither
and every credentialed verb died onN8N_HOST must be set— including the
mcp connectguard, which left agents in a worktree with non8n-instance
tools at all. A worktree without its own credentials now reads the main
checkout's copies (same path, resolved from git's own worktree pointer, no
gitsubprocess). A local file still wins, so a worktree deliberately
aimed at another instance keeps its own, and nothing else is redirected —
workflows/,.decanter.jsonanddecanter.config.jsonstay worktree-local.
For.decanter-auth.jsonthe shared file is the only correct shape: the
refresh token is single-use and rotates, so copying it into a worktree
(what Claude Code's.worktreeincludewould do) forks it into two token
chains and kills the loser. New Git
worktrees section covers the two
remaining worktree gaps decanter cannot fix — a missingnode_modulesand the
per-path MCP approval — and the troubleshooting entry for missing
n8n-instancetools gained the worktree case.