n8n-decanter 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/README.md +147 -286
  3. package/dist/lib/add.mjs +54 -44
  4. package/dist/lib/api.mjs +70 -46
  5. package/dist/lib/backup.mjs +256 -0
  6. package/dist/lib/config.mjs +28 -7
  7. package/dist/lib/datatables.mjs +124 -0
  8. package/dist/lib/engine.mjs +192 -0
  9. package/dist/lib/executions.mjs +71 -4
  10. package/dist/lib/git.mjs +10 -0
  11. package/dist/lib/init.mjs +139 -38
  12. package/dist/lib/lifecycle.mjs +16 -109
  13. package/dist/lib/mcp.mjs +636 -0
  14. package/dist/lib/mcpconnect.mjs +174 -0
  15. package/dist/lib/mcpserve.mjs +259 -0
  16. package/dist/lib/mirror.mjs +133 -0
  17. package/dist/lib/picker.mjs +41 -19
  18. package/dist/lib/preflight.mjs +442 -0
  19. package/dist/lib/pull.mjs +65 -53
  20. package/dist/lib/push.mjs +171 -63
  21. package/dist/lib/rename.mjs +41 -101
  22. package/dist/lib/run.mjs +14 -20
  23. package/dist/lib/simulate.mjs +689 -0
  24. package/dist/lib/state.mjs +33 -7
  25. package/dist/lib/status.mjs +115 -65
  26. package/dist/lib/testrun.mjs +299 -0
  27. package/dist/lib/util.mjs +5 -1
  28. package/dist/lib/validate.mjs +62 -12
  29. package/dist/lib/watch.mjs +32 -208
  30. package/dist/n8n-decanter.mjs +665 -149
  31. package/package.json +11 -4
  32. package/template/.claude/hooks/mcp-route-check.mjs.example +72 -0
  33. package/template/.claude/settings.local.json.example +24 -2
  34. package/template/.cursor/rules/n8n-decanter.mdc.example +11 -5
  35. package/template/.env.example +18 -8
  36. package/template/.mcp.json.example +7 -11
  37. package/template/AGENTS.md.example +331 -116
  38. package/template/CLAUDE.md.example +5 -3
  39. package/template/n8n-globals.d.ts.example +6 -1
  40. package/template/opencode.json.example +12 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,416 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-07-23
11
+
12
+ ### Added
13
+
14
+ - **`backup` — git-native, redeployable disaster recovery.** `n8n-decanter
15
+ backup create <workflow>` captures the workflow's full REST export into a
16
+ committed, versioned `workflows/<slug>/backups/<timestamp>.<versionId>.json`
17
+ store — the fidelity MCP can't give (credential refs + `description` kept;
18
+ `pinData`/`staticData` stripped; each Code node's `jsCode` stays a `//@file:`
19
+ placeholder, so no code is duplicated). It **dedupes** on an unchanged
20
+ `versionId` and **rolling-prunes** the working set to `backupLimit` (config,
21
+ default 20; `0` keeps all). `backup restore <workflow> [--version <id> |
22
+ --at <ts>]` re-inlines the Code from `code/` and REST-POSTs a **new,
23
+ unpublished** workflow with **node ids preserved** — a real second version
24
+ history that survives the instance being lost; it prints credential-rebind
25
+ hints + the editor URL (publish is your next step). `backup list <workflow>`
26
+ shows the retained set. REST-only: needs `N8N_API_KEY`. The backup file is
27
+ **not** auto-committed (it carries credential refs and any embedded
28
+ secrets) — review it, then `git add` deliberately.
29
+ - **Live `workflow.json` mirror — the review snapshot refreshes itself after
30
+ an agent restructures a workflow through the guard.** When a structure edit
31
+ is forwarded through `mcp connect` / `mcp serve` (a non-blocked
32
+ `update_workflow`), decanter now schedules a debounced background `pull` of
33
+ that workflow, so the read-only `workflow.json` (+ code files + state) stays
34
+ fresh with **no manual `pull`**. On by default; set `"liveMirror": false` in
35
+ `decanter.config.json` to disable (CI / deterministic setups). It is
36
+ fire-and-forget (never blocks the agent's next tool call), git-gated
37
+ (safety-commits before pulling; skips with no git), and tracked-only. This
38
+ changes `mcp connect`/`serve` default behavior (additive and disable-able —
39
+ not breaking).
40
+ - **`preflight` — the whole verification ladder as one scored, read-only
41
+ gate.** `n8n-decanter preflight [workflow…]` runs every safe check there
42
+ is — local static (`layout`, `types`) → instance read-only (`connect`,
43
+ `access`, `parity`, `drift`, `snapshot`, `lifecycle`, `history`,
44
+ `capture`) → pinned draft runs (`test`, `simulate`) — ordered fast→slow,
45
+ streaming each result, and condenses them into a **score (0–100)** and a
46
+ **verdict** (`ready` / `caution` / `not ready`, exit 0/1) with per-check
47
+ remediation. Profiles are explicit and deterministic: `--quick` (static +
48
+ sync), default (+ `test`), `--full` (+ `simulate`), `--offline` (static +
49
+ `simulate`, no instance). It brings **executions into the gate** — auto-
50
+ fetching the newest capture when `N8N_API_KEY` is set (`--no-fetch` opts
51
+ out) and reading production run health (`history`, via MCP
52
+ `search_executions` or the REST fallback). Coverage is first-class: every
53
+ skip names its unlock, and `--require=<ids>` turns a skipped check into a
54
+ hard fail; `--fail-on=warn` promotes a caution to exit 1; `--fail-fast`
55
+ stops at the first failure. `--json` emits the full report (stable check
56
+ ids + remediation strings — the agent contract). **`preflight` never
57
+ mutates** in any profile: no push, publish, restore, or draft write —
58
+ `test` runs in a never-mutate mode and `simulate` headless with
59
+ `--network-none` forced on. The single gate to run before `push`/`publish`.
60
+ - **`test` — instance-side pinned test runs (the recommended runtime
61
+ check).** `n8n-decanter test <workflow>` runs the workflow on your
62
+ instance via MCP `test_workflow`: the trigger and network/credentialed
63
+ nodes are pinned from a capture (`--execution`, default newest) or a
64
+ committed scenario (`--scenario`), logic nodes execute for real on the
65
+ instance-exact engine, and each node's output is diffed against the
66
+ capture (exit 1 on divergence; `--trigger` picks the start node,
67
+ `--json` emits the report). The run targets the **draft** — the live
68
+ version is never affected. On a terminal, when local code differs from
69
+ the draft, `test` offers to push it first (drift-guarded, draft-only)
70
+ and afterwards to keep or restore the pre-test draft (n8n version
71
+ history when available, byte-exact write-back below n8n 2.29);
72
+ non-interactive runs never mutate and say when they tested the draft
73
+ instead of local code. `simulate` stays the offline sibling —
74
+ pre-push/CI/isolation/version-rehearsal — and its docs now recommend
75
+ `test` first.
76
+ - **`mcp connect` — the stdio MCP guard, auto-wired by `init`.** The default
77
+ way a coding agent reaches your instance's MCP server: the scaffolded
78
+ `.mcp.json` (and `opencode.json`) carry a static, secret-free
79
+ `n8n-instance` entry (`{"command":"n8n-decanter","args":["mcp","connect"]}`),
80
+ so guarded instance access exists the moment `init` runs — nothing to
81
+ start, no secret to manage (stdio pipes are private). Decanter holds the
82
+ credentials; the same guard rule as `mcp serve` applies (see below).
83
+ Structure and lifecycle acts — creating/renaming/archiving workflows,
84
+ adding/renaming/wiring nodes — pass through; Code-node (`jsCode`) writes
85
+ are blocked toward the file + `push` flow. Fail-closed on unparseable
86
+ input; an unreachable instance answers the agent with a JSON-RPC error
87
+ naming the host; logs go to stderr (stdout is protocol-only).
88
+ - **`mcp serve` — the same guard as a localhost HTTP proxy**, for agents
89
+ configured by URL: decanter holds the credentials (the
90
+ agent gets a per-session secret instead), every read and structure
91
+ operation forwards untouched (SSE included), and exactly one thing is
92
+ blocked — `update_workflow` calls that write Code-node source, via either
93
+ a `jsCode` key or a `setNodeParameter` op whose path targets `jsCode`,
94
+ which get an instructive "edit the file + push" tool error. Fail-closed on unparseable
95
+ bodies, 127.0.0.1-only, body-size cap; the running endpoint + secret land
96
+ in a gitignored `.decanter-proxy.json`. The template gains a
97
+ `mcp-route-check.mjs` session hook that nudges agents whose MCP config
98
+ still points at the instance directly, and the sync-dir `AGENTS.md`
99
+ contract is now guard-first.
100
+
101
+ ### Removed
102
+
103
+ - **Breaking: the structure/lifecycle verbs are gone — `rename`, `create`,
104
+ `node create` (and its `--ts` flag), and `node rename`.** Those acts go
105
+ through **n8n itself**: the n8n editor, or n8n's MCP tools reached through
106
+ the new `mcp connect`/`mcp serve` guard (which is exactly what the
107
+ official n8n skills drive). Decanter's job is the reconcile: the next
108
+ `pull` re-caches a renamed workflow's name (folder stays put), renames a
109
+ renamed node's local file, and lands a new Code node as a source file. A
110
+ Code node added over MCP carries **no `jsCode`** (the guard blocks code in
111
+ `addNode`) — it now lands as an **empty file** whose first `push` seeds
112
+ the source, completing the guarded authoring loop. Two behaviors did not
113
+ survive the removal: `$('…')` refs inside local `.ts` sources are no
114
+ longer rewritten on a node rename (n8n never sees `.ts` — update them by
115
+ hand after the pull), and validate-before-create is now the calling
116
+ agent's discipline (`validate_workflow` first, as the n8n skills teach).
117
+ - **Breaking: the `delete` verb is gone.** Decanter no longer offers a hard
118
+ delete; retiring a workflow is an n8n act (archive it over MCP or in the
119
+ UI — reversible there, which is also where permanent deletion lives).
120
+ - **Breaking: the `duplicate` verb is gone.** MCP has no lossless full-JSON
121
+ create, so a faithful clone required the public API — rather than keep the
122
+ API dependency or ship a lossy SDK-code re-expression, the verb was
123
+ dropped. Duplicate workflows from the n8n UI and `pull` the copy.
124
+ - **Breaking: `watch`'s browser-reload proxy is gone — `browserReload` and
125
+ `proxyPort` config keys are no longer honored (silently ignored, not an
126
+ error).** n8n 2.x reflects an MCP draft edit in the open editor natively
127
+ (soft canvas re-render, skipped — with a warning — while the tab has
128
+ unsaved edits), making decanter's injected `<script>`-reload proxy
129
+ redundant and, on that exact dirty-tab path, worse than doing nothing (a
130
+ hard reload would have clobbered the unsaved edits). `watch` now just
131
+ prints the editor deep link with a note to keep the tab open; it updates
132
+ live on every push.
133
+ - **Breaking: `simulate --pin` and per-node `fixtures/` are gone — folded into
134
+ `scenario`.** The per-node `workflows/<folder>/fixtures/<node>.json`
135
+ mechanism and its precedence over captures are removed outright; a scenario
136
+ is now the only committed pin artifact and is always self-contained (no
137
+ fixture-over-capture layering to reason about). `--pin`'s job — "make a
138
+ clean capture reproducible" — is now `scenario create --execution <id>`. A
139
+ leftover `fixtures/` dir is a **hard error** from `simulate`/`check` naming
140
+ the replacement; there is no silent read-path or auto-migration for it
141
+ (unlike a leftover `mocks/` dir, which auto-migrates to `scenarios/` on
142
+ first touch — see the `scenario` namespace under Added).
143
+
144
+ ### Fixed
145
+
146
+ - **Verb-first error hints.** Several CLI error/guidance messages suggested
147
+ **verb-last** commands (`n8n-decanter <ref> simulate …`,
148
+ `n8n-decanter <ref> executions`, `n8n-decanter <ref> scenario …`) that the
149
+ verb-first grammar rejects when copy-pasted; every one now prints the
150
+ verb-first form (`n8n-decanter simulate <workflow> …`,
151
+ `n8n-decanter executions <workflow>`, `n8n-decanter scenario … <workflow>`).
152
+ - **Refresh-token race (OAuth):** two concurrent MCP calls — or `watch` plus
153
+ a manual `push` sharing `.decanter-auth.json` — could both redeem the
154
+ single-use refresh token, killing the session for the loser ("re-run
155
+ init"). Concurrent calls now share one redemption, a lost cross-process
156
+ race recovers by re-reading the winner's rotated auth file, and auth-file
157
+ writes are atomic.
158
+ - **MCP client hardening:** a transient handshake failure no longer poisons
159
+ every later call in the same run; a 200-with-HTML answer (captive
160
+ portal/reverse proxy) gets a named error instead of a raw `SyntaxError`;
161
+ body-read timeouts use the friendly timeout message; a rate-limit
162
+ `Retry-After` is honored up to n8n's verified 5-minute window (with a
163
+ visible "waiting Ns" warning) and capped there against bogus-huge
164
+ headers; a dropped MCP session (404 with a session id) re-handshakes once
165
+ transparently; a token-refresh response without a
166
+ rotated refresh token keeps the old one; workflow lists that hit the
167
+ 200-row page cap warn about truncation.
168
+ - **`init` appends `.decanter-auth.json` to a pre-existing `.gitignore`**
169
+ instead of only warning — the file holds the MCP refresh token.
170
+ - **Push verifies `.ts` nodes after the write** (marker hash vs. remote
171
+ body — catches server-side normalization), and watch's single-node pushes
172
+ run the same post-push verification as full pushes.
173
+
174
+ ### Changed
175
+
176
+ - **`pull` with no argument now opens the picker on a fresh setup.** On a
177
+ terminal, `n8n-decanter pull` (no ref) lists your workflows — **local and
178
+ remote** (over MCP) — so you can pick one to pull without knowing its id or
179
+ pre-listing it in `decanter.config.json`; picking a not-yet-local workflow
180
+ pulls it fresh. Previously its no-ref picker showed only already-pulled
181
+ workflows, so a first-ever `pull` errored with `no workflow ids`. Piped /
182
+ non-interactive runs are unchanged (they pull the config `workflows` set).
183
+ - **The scaffolded MCP config is rebuilt around the guard + n8n's official
184
+ docs MCP.** `init`'s `.mcp.json` (and `opencode.json`) now wire two
185
+ servers: **`n8n-instance`** — the `mcp connect` guard (see Added) — and
186
+ **`n8n-docs`**, n8n's first-party read-only docs MCP
187
+ (`https://docs.n8n.io/~gitbook/mcp`, public, no auth), replacing the
188
+ community `n8n-mcp` server. The docs server can't reach your instance, so
189
+ it can't bypass the guard — live workflow access goes only through
190
+ `n8n-instance`. The scaffolded Claude Code allowlist pre-approves
191
+ `mcp__n8n-docs` plus the offline/read verbs `pull`, `scenario`, and
192
+ `simulate`; instance-mutating verbs still prompt.
193
+ - **A body-equal push now re-registers a missing `@ts-n8n` marker** — when a
194
+ `.ts` node's compiled code already matches the remote but the marker is
195
+ gone (e.g. rewritten in the UI), push writes the node anyway so it is
196
+ recognized as TS-managed again (previously skipped as "in sync").
197
+ - **Converting a `.ts` node back to `.js` is now supported symmetrically:**
198
+ replace the file, re-point its `//@file:` placeholder, and push — the
199
+ push clears the remote `@ts-n8n` marker even when the code is otherwise
200
+ identical, so the node stops being TS-managed (previously the stale
201
+ marker made the next pull resurrect the node as `.ts`).
202
+ - **`scenario create` strips the capture's embedded `workflowData`** — committed
203
+ scenarios no longer duplicate every Code node's source in git; the compliance
204
+ guard warns about legacy scenarios that still embed it, and it now also flags
205
+ Python Code nodes honestly (their `pythonCode` stays inline in
206
+ `workflow.json`; extraction is a planned feature).
207
+ - **Template refresh (from the MCP pivot):** the sync-dir `AGENTS.md`
208
+ contract was rewritten around the MCP boundary (Code-node source = files +
209
+ decanter push; structure = n8n/MCP; knowledge skills recommended) with
210
+ matching `.cursor` rules, and `.env.example` is OAuth-first (MCP
211
+ credentials primary, the API key optional with a minimal scope list).
212
+ - **`N8N_API_KEY` now powers only `executions` and `data-tables`** — the last
213
+ lifecycle verbs left the REST API, so the recommended key scopes shrink to
214
+ `workflow:list`, `execution:read`, `execution:list`, and the `dataTable:*`
215
+ read scopes (`template/.env.example` was rewritten OAuth-first to match).
216
+
217
+ - **Breaking: the workflow code path now syncs over n8n's built-in MCP server —
218
+ decanter is the Code-node code layer, n8n owns structure (Plan 32).**
219
+ `pull`/`push`/`watch`/`status`/`publish`/`unpublish` ride
220
+ `POST /mcp-server/http` instead of the public REST API. What that means in
221
+ practice:
222
+ - **Pushes are draft-first.** `push` writes only each Code node's `jsCode`
223
+ (an atomic `update_workflow` batch with merge semantics) to the workflow's
224
+ **draft**; the live version never changes until an explicit `publish` — or
225
+ the new **`push --publish`**, which combines the two. The API-era
226
+ "auto-publish on push to an active workflow" behavior is gone.
227
+ - **`workflow.json` is now a read-only structure snapshot.** Pull refreshes
228
+ it for review diffs and the offline tooling; nothing pushes it. The
229
+ whole-workflow structural hashing, the structural drift guard, watch's
230
+ structural-conflict prompt (`workflow.remote.json`), and the `.remote.js`
231
+ conflict artifacts are all gone — the only drift guard left is the
232
+ per-node code check (`--force` still overrides it), and remote structure
233
+ changes never block a push (`status` prints a snapshot-stale hint instead).
234
+ - **Structure acts live in n8n.** Renames, new nodes, wiring, and new
235
+ workflows happen in the n8n editor or over n8n's MCP tools (through the
236
+ guard) — n8n rewrites connections and `$('…')` references server-side,
237
+ node ids stay stable, and the next `pull` makes local files follow.
238
+ - **Requires n8n ≥ ~2.20 with MCP access enabled**, plus a per-workflow
239
+ "Available in MCP" opt-in. The picker shows MCP-unavailable workflows as a
240
+ third state (red `⊘`, sorted last) with enable guidance instead of a
241
+ failing pull; `list --remote` marks them (`--json` adds `mcpAvailable`)
242
+ and pull/push errors carry the same guidance.
243
+ - **The public API key becomes optional.** Only the surfaces MCP cannot
244
+ serve still use it: `executions` and `data-tables` fetches. The client
245
+ retries n8n's MCP rate limiting (429) with backoff automatically.
246
+ - **Breaking: `init` is OAuth-first.** `init` now connects to the instance via
247
+ the standard MCP OAuth flow — browser consent, then a refresh token stored
248
+ in a new gitignored **`.decanter-auth.json`** (rotated on every refresh) —
249
+ with a paste-a-token fallback (`N8N_MCP_TOKEN`, minted in n8n → Settings →
250
+ MCP) for piped/headless runs. The public API key prompt is now optional.
251
+
252
+ ### Added
253
+
254
+ - **New `scenario` namespace — named, committed pin-data sets, captured and/or
255
+ schema-scaffolded.** A *gap* (a network node reached in the replay with no
256
+ pinned data) used to be a dead end. `scenario create <workflow> ["<slug>"]
257
+ [--execution <id>] [--scaffold]` writes a tracked, self-contained
258
+ **scenario** `workflows/<folder>/scenarios/<slug>.json` (slug defaults to the
259
+ execution id) and flags which nodes to fill: `--execution <id>` promotes a
260
+ gitignored capture and flags each remaining gap; `--scaffold` calls n8n's
261
+ read-only MCP tool `prepare_test_pin_data` and annotates every gap with its
262
+ output **JSON Schema** (no data — the tool is a schema oracle only); the two
263
+ compose, and a bare `--scaffold` with no capture builds a from-scratch set
264
+ where every pinnable node is a fill entry. You (or your IDE agent) add the
265
+ nodes' `runData` — **no API key, the CLI never calls a model or invents
266
+ values** — and replay it with `simulate --scenario <slug>` /
267
+ `test --scenario <slug>`. Each node's pins carry a **provenance**
268
+ (`capture`/`authored`/`scaffolded`); a run on a scenario with any
269
+ non-`capture` node is labeled "**synthetic pins — proves executability, not
270
+ output correctness**" (no per-node diff asserted; `--json` reports gain
271
+ `syntheticPins`/`provenance`), while a capture-only scenario keeps full
272
+ per-node diff and exit-1-on-divergence semantics. `scenario check <workflow>
273
+ ["<slug>"]` **structurally validates** a scenario (or all of them)
274
+ **offline** — no Docker — with a node-named error if an item is malformed or
275
+ a flagged node is left empty; `simulate --scenario`/`test --scenario` run the
276
+ same check on load. n8n publishes no execution-data JSON Schema, so decanter
277
+ checks the exact shape it replays. Committed → scenario-based replays are
278
+ reproducible for teammates and CI; `scenario create` warns about PII and
279
+ refuses to overwrite an existing scenario. A `mocks/` dir from an earlier
280
+ unreleased build auto-migrates to `scenarios/` on first touch.
281
+ - **`simulate` previews multi-batch loops in the viewer.** In an interactive
282
+ terminal, a genuine multi-batch loop (previously a hard error) now caps the
283
+ loop to its first batch and opens that single iteration in the browsable
284
+ viewer, clearly labeled *"iteration 1 of N — not a pass/fail check."* Headless
285
+ / `--json` / `--network-none` runs (scripts, CI) still hard-error, so an exit
286
+ code is never mistaken for a verified pass.
287
+
288
+ ### Fixed
289
+
290
+ - **Value-taking flags no longer swallow a following verb.** Writing a
291
+ value flag in its space-separated form without a value — e.g.
292
+ `n8n-decanter --status pull` — used to consume the `pull` verb as the
293
+ flag's value and then fail with a confusing "no verb" error. Such flags
294
+ (`--status`, `--limit`, `--execution`, `--n8n-version`, `--scenario`,
295
+ `--filter`, `--search`, `--sort`) now refuse to eat a known verb and report
296
+ `--status needs a value (e.g. --status=success)` instead.
297
+
298
+ ## [0.5.0] - 2026-07-21
299
+
300
+ ### Changed
301
+
302
+ - **Breaking: verb-first grammar.** The verb now comes first —
303
+ `n8n-decanter <verb> [workflow…]`. Verb-last (`n8n-decanter wf123 push`) is no
304
+ longer accepted and errors with *unknown verb*. Because everything after the
305
+ verb is an argument, a workflow named like a verb needs no special handling:
306
+ `n8n-decanter status push` runs `status` on the workflow named `push`. Flags
307
+ may still appear in any position.
308
+ - **Breaking: node operations moved under a `node` namespace.** `add` →
309
+ `node create <workflow> "<Node name>"`, the two-name node rename →
310
+ `node rename <workflow> "<old node>" "<new node>"`, and `run <node-file>` →
311
+ `node run <node-file>`.
312
+ - New workflow folders are **kebab-case** (`Order Sync` → `workflows/order-sync/`)
313
+ instead of keeping spaces and capitals. **Existing folders are left untouched**
314
+ and still resolve as refs — no migration, no churn.
315
+ - A workflow folder **no longer follows a remote rename**. The folder is a stable
316
+ local slug; the always-current display name lives in `.decanter.json` (see
317
+ Added). Renaming a workflow (locally or on the server) never moves your folder.
318
+
319
+ ### Added
320
+
321
+ - **`data-tables` verb** — a read-only fetch of n8n **data-table** schemas and
322
+ rows (the built-in project-scoped tables, n8n ≥ 2.x) into a top-level,
323
+ gitignored `data-tables/<table>/{meta,columns,rows}.json` dir, for developing
324
+ and debugging against real table contents offline. `--filter '<json>'`,
325
+ `--search`, and `--sort` pull only a slice of a large table server-side (the
326
+ applied filter is recorded in each table's `meta.json`); `--limit`/`--all`
327
+ control page size and exhaustion. It never writes a data table.
328
+ `data-tables clean` removes the dir (offline). Gated by the new **`dataTables`**
329
+ config key (default `true`); when off, the fetch refuses and the recommended
330
+ key needn't carry the data-table read scopes (`dataTable:list`,
331
+ `dataTable:read`, `dataTableColumn:read`, `dataTableRow:read`).
332
+ - `.decanter.json` now caches the workflow's display **`name`** (refreshed on
333
+ every pull), so the picker, `list`, and ref-resolution show the real name even
334
+ though the folder is a kebab slug — and keep working if `workflow.json` is
335
+ missing or corrupt.
336
+ - **`list --json`** emits `[{ name, id, dir }]` for tooling (remote-only
337
+ workflows under `--remote` have `dir: null`).
338
+ - **No-ref → picker.** A ref-taking verb given no workflow, on a terminal, opens
339
+ the interactive picker to choose one and runs the verb on it. Piped/non-TTY
340
+ runs keep the config-default / error behavior, so scripts and CI never block.
341
+ - **`simulate` now replays single-iteration loops.** A workflow whose only
342
+ repeated node is a `splitInBatches` ("Loop Over Items") driver that ran a
343
+ single batch — it runs twice (one batch pass + the final "done" pass) while
344
+ every other node ran once — no longer hard-errors. The loop driver executes
345
+ for real to reproduce the loop, and each node's one captured run pins exactly.
346
+
347
+ ### Removed
348
+
349
+ - **Breaking: `rename --workflow` flag.** Workflow rename is now the single
350
+ top-level form `rename <workflow> "<new name>"`; node rename lives under
351
+ `node rename`.
352
+
353
+ ## [0.4.5] - 2026-07-21
354
+
355
+ ### Added
356
+
357
+ - **`simulate` in the interactive picker.** The verb menu for a pulled workflow
358
+ now offers `simulate` alongside status/pull/push/watch/check/executions; it
359
+ runs against the workflow's newest capture.
360
+ - **Open a simulation run in the n8n webapp.** In an interactive terminal,
361
+ `simulate` prints a **URL** to the run in a kept-alive local n8n (plus the
362
+ throwaway instance's login) — pure nodes' real output and the pinned nodes,
363
+ node-by-node in the actual execution inspector. No flag, no extra step; a
364
+ fresh viewer replaces the previous one each run (`docker rm -f
365
+ decanter-sim-viewer` to stop it). Scripts, `--json`, and `--network-none`
366
+ runs stay headless and print no URL, so CI is unaffected.
367
+
368
+ ### Changed
369
+
370
+ - **`simulate` no longer requires `--execution`.** With the flag omitted it
371
+ defaults to the **newest capture** in the workflow's `executions/` dir, so
372
+ `n8n-decanter <ref> simulate` works right after an `executions` fetch (and
373
+ lets the picker offer it). Pass `--execution <id>` to pick a specific one.
374
+
375
+ ## [0.4.4] - 2026-07-21
376
+
377
+ ### Changed
378
+
379
+ - **The generated `.claude/settings.local.json` pre-approves more safe verbs.**
380
+ `rename`, `list`, `executions` (incl. `executions clean`), `completion`, and
381
+ `help` — plus a bare `status` — now run without a permission prompt, matching
382
+ the "offline, safe" and "reads remote, no writes" tiers documented in the
383
+ sync-dir `AGENTS.md`. Mutating/destructive verbs (`push`, `pull`, `watch`,
384
+ `publish`, `unpublish`, `create`, `duplicate`, `simulate`, `delete`) still
385
+ prompt, and `delete --force` is now hard-denied alongside `push --force`.
386
+
387
+ ## [0.4.3] - 2026-07-21
388
+
389
+ ### Changed
390
+
391
+ - **`$('Node').item` in the type shim (`n8n-globals.d.ts`) is no longer typed
392
+ `| undefined`.** Accessing `$('Node').item.json` no longer raises a spurious
393
+ "Object is possibly 'undefined'" (TS2532) — the value is non-undefined, like
394
+ `$input.item`, since a missing paired item throws at runtime rather than
395
+ yielding `undefined`. Use `itemMatching(i)`, `first()`, or `last()` when you
396
+ want an index-checked lookup instead.
397
+
398
+ ## [0.4.2] - 2026-07-20
399
+
400
+ ### Added
401
+
402
+ - **`simulate` verb** — `n8n-decanter <ref> simulate --execution <id>` replays
403
+ a whole workflow through a **real n8n engine** (Docker) using a captured
404
+ execution as the mock: side-effect-free nodes (Set, IF, Code, …) execute for
405
+ real, every network/side-effectful node is pinned to its captured output,
406
+ credentials are stripped, and no outbound-capable node survives — a dry,
407
+ engine-true regression check. It diffs each executed node's output against the
408
+ capture and **exits `1` on divergence** (CI-gateable). `--network-none` adds
409
+ an enforced outbound cutoff; `--json` emits the report for tooling.
410
+ - **`simulate --pin <id>`** — copy a capture's network-node outputs into
411
+ committed, provenance-stamped `workflows/<Name>/fixtures/<node>.json`, making
412
+ replays reproducible and committable (prints a PII-review warning).
413
+ - **`n8nVersion` config field** (`decanter.config.json`) — pins the n8n version
414
+ the `simulate` engine runs, so "engine-true" matches your instance;
415
+ `--n8n-version <tag>` overrides it per run. Defaults to the project's pinned
416
+ version with a hint when unset.
417
+ - **`npm run test:sim`** — opt-in engine simulation suite (needs Docker; never
418
+ part of `npm test`); skips cleanly when no Docker daemon is available.
419
+
10
420
  ## [0.4.1] - 2026-07-20
11
421
 
12
422
  ### Changed