@manny-est/node-red-flowpilot 0.5.2 → 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.
- package/CHANGELOG.md +85 -26
- package/README.md +10 -1
- package/USER-GUIDE.md +5 -1
- package/flowpilot-core.css +53 -10
- package/flowpilot-node-entry.js +15 -0
- package/flowpilot.js +1207 -187
- package/lib/agent-contract.js +50 -0
- package/lib/build-core-script.js +1 -0
- package/lib/chat-data.js +106 -0
- package/lib/core/apply-review.js +34 -11
- package/lib/core/graph-truth.js +63 -0
- package/lib/core/history.js +157 -6
- package/lib/core/init.js +223 -21
- package/lib/core/main.js +780 -38
- package/lib/core/modes.js +1098 -112
- package/lib/core/selection-context.js +44 -24
- package/lib/default-system-prompt.js +4 -3
- package/lib/document-system-prompt.js +7 -4
- package/lib/envelope.js +13 -7
- package/lib/generation-system-prompt.js +5 -4
- package/lib/modify-system-prompt.js +64 -12
- package/lib/persona-prompt.js +81 -54
- package/lib/prompt-fragments.js +17 -2
- package/lib/provider-anthropic.js +23 -10
- package/lib/provider-openai-compatible.js +51 -11
- package/lib/provider-shape-check.js +34 -0
- package/lib/storage.js +134 -21
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to FlowPilot are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.6.0] - 2026-09-01
|
|
6
|
+
|
|
7
|
+
Promoted from `0.6.0-beta.1` to the stable `latest` npm tag.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Agentic WRITE-tool loop for Modify and Generate** (behind the
|
|
11
|
+
`enableAgentWrite` setting, default off): step-by-step tool calls
|
|
12
|
+
against the live flow (`apply_step`, `remove_step`, `rename_node`,
|
|
13
|
+
`group_nodes`), each write-gated by a per-step consent prompt (Proceed
|
|
14
|
+
/ Skip this step) before it touches the canvas. Multi-item requests are
|
|
15
|
+
tracked and executed as separate, individually-verified steps rather
|
|
16
|
+
than one all-or-nothing envelope; an injected mid-run failure (e.g. a
|
|
17
|
+
referenced node no longer exists) fails only that item, with the rest
|
|
18
|
+
completing normally. Generate joined the same agentic runtime Modify
|
|
19
|
+
already used, closing the last place a mutation could land through the
|
|
20
|
+
older, less-verified classic JSON path while write-tool mode is on.
|
|
21
|
+
- **`ask_user` clarifying-question tool**: an agent-strategy turn can pause
|
|
22
|
+
mid-run to ask a single focused question (with optional quick-reply
|
|
23
|
+
buttons) instead of guessing, and resumes exactly where it left off once
|
|
24
|
+
answered.
|
|
25
|
+
- **Deterministic run summaries**: when a Modify or Generate run actually
|
|
26
|
+
applied WRITE-tool steps, the per-item outcome you see (✓ applied and
|
|
27
|
+
verified / ✗ failed, with why) now comes straight from what the tools
|
|
28
|
+
actually reported — not from the model's own retelling. The model's own
|
|
29
|
+
wrap-up explanation still shows, underneath, clearly secondary — useful
|
|
30
|
+
context, never the thing you have to trust to know what really
|
|
31
|
+
happened.
|
|
32
|
+
- **Contract-exclusivity enforcement**: a server-side safety net
|
|
33
|
+
(`enforceAgentContract`) strips any classic-style mutation fields
|
|
34
|
+
(`changes`/`newNodes`/`newWires`/`removeNodes`/`newGroups`/`flow`) that
|
|
35
|
+
accidentally appear on an agent-strategy turn with no tool calls, before
|
|
36
|
+
they ever reach the client — the two mutation paths (classic envelope vs.
|
|
37
|
+
agentic WRITE tools) stay mutually exclusive per turn, for every mode
|
|
38
|
+
that can run agentically.
|
|
39
|
+
- **Run identity and honest interruption**: agent-strategy runs now carry a
|
|
40
|
+
stable run/operation id so a duplicate tool-call delivery (a retry, or the
|
|
41
|
+
model repeating itself) is applied at most once; a run that's stopped or
|
|
42
|
+
hits its step/token ceiling reports an honest "interrupted after N steps"
|
|
43
|
+
instead of silently truncating. That step-by-step record is also now
|
|
44
|
+
visible to the server (previously client-side only), the foundation for
|
|
45
|
+
the deterministic run summaries above.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- **The FlowPilot sidebar's entire client script was loading twice on
|
|
49
|
+
every single editor page load** — a packaging issue present since the
|
|
50
|
+
plugin's first release, only now found and fixed. In practice this
|
|
51
|
+
meant a page reload silently lost the current conversation (a second,
|
|
52
|
+
redundant script execution would stomp the first one's restored state)
|
|
53
|
+
and, more subtly, any other one-time setup code in the client ran
|
|
54
|
+
twice per load. Reloading the Node-RED editor now correctly picks the
|
|
55
|
+
conversation back up where you left off.
|
|
56
|
+
- Anthropic (Claude) responses now get the exact same deterministic
|
|
57
|
+
run-summary and contract-exclusivity treatment as every other
|
|
58
|
+
provider — verified directly against Claude Sonnet, not just the
|
|
59
|
+
OpenAI-compatible path.
|
|
60
|
+
|
|
61
|
+
### Security
|
|
62
|
+
- **API keys are now write-only over HTTP** (previously exposed on
|
|
63
|
+
`GET`/`POST /flowpilot/settings` — a fork-hygiene regression from the
|
|
64
|
+
0.5.1 stable line, now ported forward and closed for good). Every
|
|
65
|
+
provider's `apiKey` is masked to a sentinel or `""` in both responses;
|
|
66
|
+
the real key never leaves the server. `settings.json` and per-conversation
|
|
67
|
+
transcripts are now created with `0600` permissions.
|
|
68
|
+
- **Provider-confirmation gate (SSRF mitigation)**: no chat, generate,
|
|
69
|
+
modify, document, build, agent-step, or model-list request reaches a
|
|
70
|
+
configured provider's Base URL until that exact URL has passed a real
|
|
71
|
+
FlowPilot connection check (Pre-flight check / Test Provider). The check
|
|
72
|
+
itself is blind on failure — a non-provider target's response is never
|
|
73
|
+
reflected back to the client — so pointing a provider at an unintended
|
|
74
|
+
internal address yields nothing readable. Confirmation is tied to the
|
|
75
|
+
exact URL and clears automatically if the Base URL or API key changes.
|
|
76
|
+
See `dev-docs/decisions/ADR-007-Provider-Confirmation-Gate.md` for the
|
|
77
|
+
full design.
|
|
78
|
+
- **Audit-trail completeness**: an agent-strategy request whose very first
|
|
79
|
+
model turn is a tool call (rather than a later continuation) is now
|
|
80
|
+
always recorded to the audit log — previously this specific case left no
|
|
81
|
+
trace at all.
|
|
82
|
+
|
|
83
|
+
### Internal
|
|
84
|
+
- Phase 10: strategy propagation, contract-exclusivity enforcement, agent
|
|
85
|
+
turn output caps, run identity/idempotency, and verification consolidation
|
|
86
|
+
across the classic and agentic Modify paths. Full history in
|
|
87
|
+
`dev-docs/current/Phase10-Build-Progress.md` and
|
|
88
|
+
`dev-docs/current/Phase10-Gate-Closeout-Final.md`.
|
|
89
|
+
|
|
5
90
|
## [0.5.2] - 2026-08-04
|
|
6
91
|
|
|
7
92
|
This release continues the 0.5.x line. Phase 10's agentic Modify redesign
|
|
@@ -39,32 +124,6 @@ until it's ready to replace this one.
|
|
|
39
124
|
the canvas.
|
|
40
125
|
|
|
41
126
|
### Fixed
|
|
42
|
-
- **Build loop — status-only evidence false negatives**: a live, working
|
|
43
|
-
node could be declared "disconnected"/broken off a single coarse
|
|
44
|
-
node-status read, with no way to confirm otherwise. Evidence is now
|
|
45
|
-
tagged by source (`debug` vs. `status`); when only status-line evidence
|
|
46
|
-
is available and it doesn't clearly prove success or failure, the build
|
|
47
|
-
loop asks a direct yes/no confirmation instead of guessing.
|
|
48
|
-
- **Modify's wire verification** read a node's stale `.wires` array
|
|
49
|
-
instead of the live link registry — a wire added earlier in the same
|
|
50
|
-
editing session could be reported as "did not land" even though it was
|
|
51
|
-
actually there. Verification now reads from `RED.nodes.eachLink`.
|
|
52
|
-
- **Phantom output port on newly-created nodes**: a model-supplied
|
|
53
|
-
`wires` array that disagreed with a node type's real port count (e.g.
|
|
54
|
-
a stray empty port on a 0-output type like `http response`) rendered a
|
|
55
|
-
visible port anchor that shouldn't exist. The array length is now
|
|
56
|
-
reconciled against the node's real output count on insertion.
|
|
57
|
-
- **New-node layout scatter**: the collision-avoidance grid still placed
|
|
58
|
-
two nodes at the same vertical level; switched to a single-column
|
|
59
|
-
layout (one node per row, wrap to a new column after 5 rows).
|
|
60
|
-
- **`newWires` endpoint aliases**: a model response using `fromId`/`toId`
|
|
61
|
-
instead of `from`/`to` on a `newWires` entry is now repaired
|
|
62
|
-
automatically instead of both endpoints silently appearing missing.
|
|
63
|
-
- **`.fp-chip-card-alt` background**: the secondary "Just add to canvas"
|
|
64
|
-
chip relied on its surrounding message bubble being dark to read as
|
|
65
|
-
part of the same chip-card family as the primary action above it —
|
|
66
|
-
bubbles follow Node-RED's light editor theme by default, so it rendered
|
|
67
|
-
as a plain white box instead.
|
|
68
127
|
- Redaction round-trip poisoning, token-credential redaction gaps, and
|
|
69
128
|
several redaction echo/false-positive fixes across Modify and the build
|
|
70
129
|
loop's review step.
|
package/README.md
CHANGED
|
@@ -26,7 +26,9 @@ installation, the sidebar UI, and a chapter on every feature.
|
|
|
26
26
|
- **User-initiated only** — FlowPilot never changes your flow without an
|
|
27
27
|
explicit request.
|
|
28
28
|
- **Complete visibility** — every proposed change is shown as a diff/review
|
|
29
|
-
before
|
|
29
|
+
before it's applied; in the opt-in agentic mode (below), each step is
|
|
30
|
+
gated by its own Proceed/Skip prompt instead, so you're still in control
|
|
31
|
+
of what actually lands on the canvas.
|
|
30
32
|
- **Undo first** — every change goes through Node-RED's native undo
|
|
31
33
|
(Ctrl+Z), including multi-part changes (insertions + rewires + new nodes)
|
|
32
34
|
as a single step.
|
|
@@ -73,6 +75,13 @@ See the [User Guide](USER-GUIDE.md#privacy-and-safety) for the full details.
|
|
|
73
75
|
Document, with a clear notice when older messages are truncated.
|
|
74
76
|
- **Clarifying questions** — if an instruction is too vague to act on
|
|
75
77
|
safely, FlowPilot asks ONE question instead of guessing.
|
|
78
|
+
- **Agentic mode (opt-in, Settings)** — Generate and Modify can work
|
|
79
|
+
step by step instead of one big review-then-apply diff: each step
|
|
80
|
+
(insert, rewire, rename, remove, group) lands on the canvas as it's
|
|
81
|
+
proposed, gated by its own Proceed/Skip consent prompt for anything
|
|
82
|
+
beyond the safest node types. The summary you see when a run finishes
|
|
83
|
+
is built from what the tools actually reported happened, not just the
|
|
84
|
+
model's own retelling — if a step failed or was skipped, it says so.
|
|
76
85
|
- **Streaming replies** — optional SSE streaming for chat responses.
|
|
77
86
|
- **`/build`** — describe a goal and FlowPilot plans it, proposes a first
|
|
78
87
|
flow, then walks an interactive build → deploy → debug → review → fix loop
|
package/USER-GUIDE.md
CHANGED
|
@@ -134,7 +134,11 @@ OpenAI-compatible endpoint), LM Studio, etc.
|
|
|
134
134
|

|
|
135
135
|
|
|
136
136
|
4. Click **Pre-flight check**. This saves your settings and sends a small
|
|
137
|
-
test request. A reply in the chat panel means you're connected.
|
|
137
|
+
test request. A reply in the chat panel means you're connected. **This
|
|
138
|
+
step is required** — a provider must pass Pre-flight check before Chat,
|
|
139
|
+
Generate, Modify, Document, or Build will send it anything; a provider
|
|
140
|
+
you just added or just changed the Base URL/API key on starts
|
|
141
|
+
unconfirmed until this check passes again.
|
|
138
142
|
|
|
139
143
|

|
|
140
144
|
|
package/flowpilot-core.css
CHANGED
|
@@ -108,6 +108,21 @@
|
|
|
108
108
|
border-color: rgba(80, 130, 255, 0.35);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/* Subordinate to the deterministic run summary above it (C1): same shape,
|
|
112
|
+
visibly de-emphasized so a model's free-text recap can't be mistaken for
|
|
113
|
+
the authoritative per-item outcome. */
|
|
114
|
+
.fp-secondary {
|
|
115
|
+
padding: 8px 14px;
|
|
116
|
+
background: transparent;
|
|
117
|
+
border-style: dashed;
|
|
118
|
+
font-size: 12px;
|
|
119
|
+
color: var(--red-ui-secondary-text-color, #888);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.fp-secondary .fp-label {
|
|
123
|
+
opacity: 0.7;
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
/* Reasoning / thinking block — shown for models that emit reasoning_content
|
|
112
127
|
(e.g. Nemotron, DeepSeek-R1). Sits above the assistant response bubble.
|
|
113
128
|
Expanded while the model thinks; collapses automatically when content starts. */
|
|
@@ -249,7 +264,7 @@
|
|
|
249
264
|
padding: 4px 0;
|
|
250
265
|
}
|
|
251
266
|
|
|
252
|
-
.fp-typing span:not(.fp-typing-label) {
|
|
267
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed) {
|
|
253
268
|
width: 7px;
|
|
254
269
|
height: 7px;
|
|
255
270
|
border-radius: 50%;
|
|
@@ -258,8 +273,15 @@
|
|
|
258
273
|
animation: fp-bounce 1.2s infinite ease-in-out;
|
|
259
274
|
}
|
|
260
275
|
|
|
261
|
-
|
|
262
|
-
|
|
276
|
+
/* CLAUDE-033: matches the base rule's :not() clauses too, so specificity
|
|
277
|
+
(0,4,1) beats the base rule's (0,3,1) — otherwise the base rule's
|
|
278
|
+
"animation" SHORTHAND implicitly resets animation-delay back to 0s on
|
|
279
|
+
every dot regardless of source order, since shorthand properties reset
|
|
280
|
+
unspecified sub-values, and CSS resolves same-property conflicts by
|
|
281
|
+
specificity first. Without this, all three dots silently bounce in
|
|
282
|
+
perfect sync instead of staggered. */
|
|
283
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed):nth-child(2) { animation-delay: 0.18s; }
|
|
284
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed):nth-child(3) { animation-delay: 0.36s; }
|
|
263
285
|
|
|
264
286
|
.fp-typing-label {
|
|
265
287
|
font-size: 11px;
|
|
@@ -268,6 +290,12 @@
|
|
|
268
290
|
align-self: center;
|
|
269
291
|
}
|
|
270
292
|
|
|
293
|
+
.fp-typing-elapsed {
|
|
294
|
+
font-size: 11px;
|
|
295
|
+
color: var(--red-ui-secondary-text-color, #999);
|
|
296
|
+
align-self: center;
|
|
297
|
+
}
|
|
298
|
+
|
|
271
299
|
.fp-agent-stop {
|
|
272
300
|
margin-left: 8px;
|
|
273
301
|
align-self: center;
|
|
@@ -371,15 +399,11 @@
|
|
|
371
399
|
font-size: 16px;
|
|
372
400
|
}
|
|
373
401
|
|
|
374
|
-
/* Secondary/escape-hatch variant:
|
|
402
|
+
/* Secondary/escape-hatch variant: transparent background, muted text.
|
|
375
403
|
Same hover glow as fp-chip-card so it reads as part of the same family
|
|
376
|
-
without competing visually with the primary action above it.
|
|
377
|
-
background, not transparent — .fp-message's surrounding bubble follows
|
|
378
|
-
Node-RED's light editor theme variable by default, so "transparent"
|
|
379
|
-
showed through as plain white instead of blending into a dark parent
|
|
380
|
-
that doesn't actually exist. */
|
|
404
|
+
without competing visually with the primary action above it. */
|
|
381
405
|
.fp-chip-card.fp-chip-card-alt {
|
|
382
|
-
background:
|
|
406
|
+
background: transparent;
|
|
383
407
|
border-color: #2a333c;
|
|
384
408
|
color: #8a96a3;
|
|
385
409
|
}
|
|
@@ -388,6 +412,14 @@
|
|
|
388
412
|
font-weight: 500;
|
|
389
413
|
}
|
|
390
414
|
.fp-chip-card.fp-chip-card-alt:hover {
|
|
415
|
+
/* CLAUDE-031: this variant's background stays transparent at rest by
|
|
416
|
+
design, so on Node-RED's LIGHT theme it inherits a white/near-white
|
|
417
|
+
surrounding background — the near-white hover text below then had
|
|
418
|
+
nothing dark to sit on and became unreadable. A solid dark fill on
|
|
419
|
+
hover (paired with the same green glow as the primary chip) fixes
|
|
420
|
+
contrast regardless of the surrounding theme, without touching the
|
|
421
|
+
transparent, theme-following look at rest. */
|
|
422
|
+
background: #141a21;
|
|
391
423
|
border-color: #46d39a;
|
|
392
424
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1px #46d39a, 0 0 14px -2px #46d39a;
|
|
393
425
|
color: #dfe6ee;
|
|
@@ -722,6 +754,17 @@
|
|
|
722
754
|
.fp-todo-item-done { color: #1a7a1a; }
|
|
723
755
|
.fp-todo-item-failed { color: #b22222; }
|
|
724
756
|
|
|
757
|
+
/* P10-D2: honest-interruption notice appended inside a "todo" record whose
|
|
758
|
+
last run event isn't "done" (see rerenderTodoRecord, modes.js). */
|
|
759
|
+
.fp-todo-interrupted {
|
|
760
|
+
margin-top: 6px;
|
|
761
|
+
padding: 4px 8px;
|
|
762
|
+
border-radius: 4px;
|
|
763
|
+
font-size: 12px;
|
|
764
|
+
background: rgba(200, 140, 0, 0.10);
|
|
765
|
+
color: #8a5a00;
|
|
766
|
+
}
|
|
767
|
+
|
|
725
768
|
.fp-json-toolbar {
|
|
726
769
|
display: flex;
|
|
727
770
|
justify-content: flex-end;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Node-RED's "nodes" registration entry needs its own .js file, separate
|
|
2
|
+
// from flowpilot.js — Node-RED derives an editor-template path for every
|
|
3
|
+
// declared "nodes" entry by replacing the .js extension with .html
|
|
4
|
+
// (@node-red/registry/lib/loader.js loadNodeConfig: `file.replace(/\.c?js$/,".html")`),
|
|
5
|
+
// with NO awareness of the "plugins" entry that already explicitly declares
|
|
6
|
+
// flowpilot.html. If this entry pointed at flowpilot.js directly, Node-RED
|
|
7
|
+
// would derive "flowpilot.html" as this node's own template, find the real
|
|
8
|
+
// file (same basename), and load its content a SECOND time — the plugin's
|
|
9
|
+
// entire client bundle (flowpilot/core.js and its inline init script)
|
|
10
|
+
// ends up in the editor page twice, executing every module-level
|
|
11
|
+
// side effect (including sessionStorage init) twice per page load.
|
|
12
|
+
// This shim's own basename ("flowpilot-node-entry") has no matching .html,
|
|
13
|
+
// so Node-RED's template lookup misses (ENOENT) and loads no content for
|
|
14
|
+
// it — exactly what a route-registration-only, no-editor-UI node needs.
|
|
15
|
+
module.exports = require("./flowpilot.js");
|