@manny-est/node-red-flowpilot 0.5.1 → 0.6.0-beta.1
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 +58 -0
- package/README.md +21 -7
- package/USER-GUIDE.md +27 -14
- package/flowpilot-core.css +159 -5
- package/flowpilot.js +1353 -172
- package/lib/agent-contract.js +45 -0
- package/lib/build-core-script.js +1 -0
- package/lib/build-system-prompt.js +26 -4
- package/lib/chat-data.js +106 -0
- package/lib/core/apply-review.js +268 -64
- package/lib/core/graph-truth.js +63 -0
- package/lib/core/history.js +10 -1
- package/lib/core/init.js +148 -5
- package/lib/core/main.js +755 -21
- package/lib/core/modes.js +1523 -67
- package/lib/core/selection-context.js +31 -1
- package/lib/default-system-prompt.js +17 -12
- package/lib/document-system-prompt.js +22 -32
- package/lib/envelope.js +13 -7
- package/lib/generation-system-prompt.js +29 -44
- package/lib/modify-system-prompt.js +152 -72
- package/lib/persona-prompt.js +81 -54
- package/lib/prompt-fragments.js +56 -0
- package/lib/provider-anthropic.js +388 -0
- package/lib/provider-openai-compatible.js +49 -12
- package/lib/provider-shape-check.js +34 -0
- package/lib/storage.js +160 -12
- package/lib/validator.js +238 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to FlowPilot are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.6.0-beta.1] - 2026-08-31
|
|
6
|
+
|
|
7
|
+
Prerelease — published to the `beta` npm tag only. `latest` stays on `0.5.2`.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Agentic WRITE-tool loop for Modify** (behind the `enableAgentWrite`
|
|
11
|
+
setting, default off): step-by-step tool calls against the live flow
|
|
12
|
+
(`apply_step`, `remove_step`, `rename_node`, `group_nodes`), each
|
|
13
|
+
write-gated by a per-step consent prompt (Proceed / Skip this step) before
|
|
14
|
+
it touches the canvas. Multi-item requests are tracked and executed as
|
|
15
|
+
separate, individually-verified steps rather than one all-or-nothing
|
|
16
|
+
envelope; an injected mid-run failure (e.g. a referenced node no longer
|
|
17
|
+
exists) fails only that item, with the rest completing normally.
|
|
18
|
+
- **`ask_user` clarifying-question tool**: an agent-strategy turn can pause
|
|
19
|
+
mid-run to ask a single focused question (with optional quick-reply
|
|
20
|
+
buttons) instead of guessing, and resumes exactly where it left off once
|
|
21
|
+
answered.
|
|
22
|
+
- **Contract-exclusivity enforcement**: a server-side safety net
|
|
23
|
+
(`enforceAgentContract`) strips any classic-style mutation fields
|
|
24
|
+
(`changes`/`newNodes`/`newWires`/`removeNodes`/`newGroups`) that
|
|
25
|
+
accidentally appear on an agent-strategy turn with no tool calls, before
|
|
26
|
+
they ever reach the client — the two mutation paths (classic envelope vs.
|
|
27
|
+
agentic WRITE tools) stay mutually exclusive per turn.
|
|
28
|
+
- **Run identity and honest interruption**: agent-strategy runs now carry a
|
|
29
|
+
stable run/operation id so a duplicate tool-call delivery (a retry, or the
|
|
30
|
+
model repeating itself) is applied at most once; a run that's stopped or
|
|
31
|
+
hits its step/token ceiling reports an honest "interrupted after N steps"
|
|
32
|
+
instead of silently truncating.
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
- **API keys are now write-only over HTTP** (previously exposed on
|
|
36
|
+
`GET`/`POST /flowpilot/settings` — a fork-hygiene regression from the
|
|
37
|
+
0.5.1 stable line, now ported forward and closed for good). Every
|
|
38
|
+
provider's `apiKey` is masked to a sentinel or `""` in both responses;
|
|
39
|
+
the real key never leaves the server. `settings.json` and per-conversation
|
|
40
|
+
transcripts are now created with `0600` permissions.
|
|
41
|
+
- **Provider-confirmation gate (SSRF mitigation)**: no chat, generate,
|
|
42
|
+
modify, document, build, agent-step, or model-list request reaches a
|
|
43
|
+
configured provider's Base URL until that exact URL has passed a real
|
|
44
|
+
FlowPilot connection check (Pre-flight check / Test Provider). The check
|
|
45
|
+
itself is blind on failure — a non-provider target's response is never
|
|
46
|
+
reflected back to the client — so pointing a provider at an unintended
|
|
47
|
+
internal address yields nothing readable. Confirmation is tied to the
|
|
48
|
+
exact URL and clears automatically if the Base URL or API key changes.
|
|
49
|
+
See `dev-docs/decisions/ADR-007-Provider-Confirmation-Gate.md` for the
|
|
50
|
+
full design.
|
|
51
|
+
- **Audit-trail completeness**: an agent-strategy request whose very first
|
|
52
|
+
model turn is a tool call (rather than a later continuation) is now
|
|
53
|
+
always recorded to the audit log — previously this specific case left no
|
|
54
|
+
trace at all.
|
|
55
|
+
|
|
56
|
+
### Internal
|
|
57
|
+
- Phase 10: strategy propagation, contract-exclusivity enforcement, agent
|
|
58
|
+
turn output caps, run identity/idempotency, and verification consolidation
|
|
59
|
+
across the classic and agentic Modify paths. Full history in
|
|
60
|
+
`dev-docs/current/Phase10-Build-Progress.md` and
|
|
61
|
+
`dev-docs/current/Phase10-Gate-Closeout-Final.md`.
|
|
62
|
+
|
|
5
63
|
## [0.5.1] - 2026-07-24
|
|
6
64
|
|
|
7
65
|
### Added
|
package/README.md
CHANGED
|
@@ -6,9 +6,10 @@ FlowPilot: AI assistance for Node-RED, designed for builders who want help
|
|
|
6
6
|
without giving up control.
|
|
7
7
|
|
|
8
8
|
FlowPilot is an AI-powered development assistant that lives in the Node-RED
|
|
9
|
-
editor sidebar. It talks to
|
|
10
|
-
Ollama, etc.) and helps you
|
|
11
|
-
flows — without ever acting
|
|
9
|
+
editor sidebar. It talks natively to Anthropic (Claude models) or to any
|
|
10
|
+
OpenAI-compatible API (OpenAI, LocalAI, Ollama, etc.) and helps you
|
|
11
|
+
generate, modify, document, and discuss your flows — without ever acting
|
|
12
|
+
behind your back.
|
|
12
13
|
|
|
13
14
|

|
|
14
15
|
|
|
@@ -29,8 +30,8 @@ installation, the sidebar UI, and a chapter on every feature.
|
|
|
29
30
|
- **Undo first** — every change goes through Node-RED's native undo
|
|
30
31
|
(Ctrl+Z), including multi-part changes (insertions + rewires + new nodes)
|
|
31
32
|
as a single step.
|
|
32
|
-
- **Open architecture** — provider-agnostic
|
|
33
|
-
lock-in to one AI platform.
|
|
33
|
+
- **Open architecture** — provider-agnostic: native Anthropic support, or
|
|
34
|
+
any OpenAI-compatible REST endpoint. No lock-in to one AI platform.
|
|
34
35
|
- **Simple and lightweight** — favors simple, maintainable solutions over
|
|
35
36
|
speculative complexity.
|
|
36
37
|
|
|
@@ -129,11 +130,24 @@ under `<node-red-userDir>/flowpilot/`:
|
|
|
129
130
|
- `chats/` — lightweight per-session chat logs
|
|
130
131
|
- `backups/` — pre-change backups
|
|
131
132
|
|
|
132
|
-
## Provider setup
|
|
133
|
+
## Provider setup
|
|
133
134
|
|
|
134
135
|
Open the FlowPilot sidebar, click the settings (gear) icon, and add a
|
|
135
|
-
provider
|
|
136
|
+
provider.
|
|
136
137
|
|
|
138
|
+
**Anthropic (Claude models):**
|
|
139
|
+
|
|
140
|
+
- Provider type: `Anthropic`
|
|
141
|
+
- Provider name: `Claude` (or any label)
|
|
142
|
+
- Base URL: leave blank (uses `api.anthropic.com`)
|
|
143
|
+
- API key: your Anthropic API key. If it returns an
|
|
144
|
+
`anthropic-workspace-id is required` error, create a new key in the
|
|
145
|
+
Anthropic Console scoped to a single workspace.
|
|
146
|
+
- Model: e.g. `claude-opus-5`, or click **Refresh models**
|
|
147
|
+
|
|
148
|
+
**Example: LocalAI (OpenAI-compatible):**
|
|
149
|
+
|
|
150
|
+
- Provider type: `OpenAI-compatible`
|
|
137
151
|
- Provider name: `LocalAI` (or any label)
|
|
138
152
|
- Base URL: `http://localhost:8080`
|
|
139
153
|
- API key: blank unless your instance requires one
|
package/USER-GUIDE.md
CHANGED
|
@@ -103,29 +103,42 @@ saved transcript permanently.
|
|
|
103
103
|
|
|
104
104
|
## Set a Provider
|
|
105
105
|
|
|
106
|
-
FlowPilot talks to
|
|
107
|
-
|
|
106
|
+
FlowPilot talks to **Anthropic** (Claude models) natively, or to any
|
|
107
|
+
**OpenAI-compatible** API — OpenAI itself, LocalAI, Ollama (with its
|
|
108
|
+
OpenAI-compatible endpoint), LM Studio, etc.
|
|
108
109
|
|
|
109
110
|
1. Open **Settings** (gear icon).
|
|
110
111
|
2. Under **Providers**, click **+ Add** if you need a new provider slot
|
|
111
112
|
(one is created for you by default).
|
|
112
|
-
3.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
3. Pick a **Provider Type**: `OpenAI-compatible` (the default) or
|
|
114
|
+
`Anthropic`.
|
|
115
|
+
4. Fill in:
|
|
116
|
+
- **Provider Name** — any label, e.g. `LocalAI`, `OpenAI`, or `Claude`.
|
|
117
|
+
- **Base URL** —
|
|
118
|
+
- OpenAI-compatible: e.g. `http://localhost:8080` or
|
|
119
|
+
`https://api.openai.com`. If Node-RED is running in Docker,
|
|
120
|
+
`localhost` refers to the *Node-RED container*, not the Docker
|
|
121
|
+
host — use the provider's container name, a Docker network alias,
|
|
122
|
+
or a host IP (e.g. `http://172.17.0.1:8080`) instead.
|
|
123
|
+
- Anthropic: leave blank to use `api.anthropic.com` — only set this
|
|
124
|
+
if you're routing through a proxy or gateway.
|
|
125
|
+
- **API Key** — for OpenAI-compatible, leave blank unless your provider
|
|
126
|
+
requires one. For Anthropic, this is required. If your key returns
|
|
127
|
+
an `anthropic-workspace-id is required` error, it wasn't scoped to a
|
|
128
|
+
single workspace when created — go to the Anthropic Console, create a
|
|
129
|
+
new key, and choose a specific workspace at creation time.
|
|
130
|
+
- **Model** — type a model name, or click **Refresh models** to fetch
|
|
131
|
+
the provider's available models and pick from the list.
|
|
123
132
|
- **Temperature** — a starting value of `0.2` works well for most uses.
|
|
124
133
|
|
|
125
134
|

|
|
126
135
|
|
|
127
136
|
4. Click **Pre-flight check**. This saves your settings and sends a small
|
|
128
|
-
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.
|
|
129
142
|
|
|
130
143
|

|
|
131
144
|
|
package/flowpilot-core.css
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
.fp-header-row {
|
|
17
17
|
display: flex;
|
|
18
|
+
flex-wrap: wrap;
|
|
18
19
|
align-items: center;
|
|
19
20
|
gap: 12px;
|
|
20
21
|
}
|
|
@@ -49,8 +50,12 @@
|
|
|
49
50
|
.fp-view-buttons {
|
|
50
51
|
display: flex;
|
|
51
52
|
gap: 6px;
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
/* Own row below the logo/title/subtitle at default (narrow) sidebar
|
|
54
|
+
width — sharing the row with .fp-heading left too little space for
|
|
55
|
+
"AI flow assistant" to fit on one line, so it wrapped across three. */
|
|
56
|
+
flex: 1 0 100%;
|
|
57
|
+
justify-content: flex-end;
|
|
58
|
+
margin-top: 8px;
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
.fp-panel {
|
|
@@ -244,7 +249,7 @@
|
|
|
244
249
|
padding: 4px 0;
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
.fp-typing span:not(.fp-typing-label) {
|
|
252
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed) {
|
|
248
253
|
width: 7px;
|
|
249
254
|
height: 7px;
|
|
250
255
|
border-radius: 50%;
|
|
@@ -253,8 +258,15 @@
|
|
|
253
258
|
animation: fp-bounce 1.2s infinite ease-in-out;
|
|
254
259
|
}
|
|
255
260
|
|
|
256
|
-
|
|
257
|
-
|
|
261
|
+
/* CLAUDE-033: matches the base rule's :not() clauses too, so specificity
|
|
262
|
+
(0,4,1) beats the base rule's (0,3,1) — otherwise the base rule's
|
|
263
|
+
"animation" SHORTHAND implicitly resets animation-delay back to 0s on
|
|
264
|
+
every dot regardless of source order, since shorthand properties reset
|
|
265
|
+
unspecified sub-values, and CSS resolves same-property conflicts by
|
|
266
|
+
specificity first. Without this, all three dots silently bounce in
|
|
267
|
+
perfect sync instead of staggered. */
|
|
268
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed):nth-child(2) { animation-delay: 0.18s; }
|
|
269
|
+
.fp-typing span:not(.fp-typing-label):not(.fp-typing-elapsed):nth-child(3) { animation-delay: 0.36s; }
|
|
258
270
|
|
|
259
271
|
.fp-typing-label {
|
|
260
272
|
font-size: 11px;
|
|
@@ -263,6 +275,12 @@
|
|
|
263
275
|
align-self: center;
|
|
264
276
|
}
|
|
265
277
|
|
|
278
|
+
.fp-typing-elapsed {
|
|
279
|
+
font-size: 11px;
|
|
280
|
+
color: var(--red-ui-secondary-text-color, #999);
|
|
281
|
+
align-self: center;
|
|
282
|
+
}
|
|
283
|
+
|
|
266
284
|
.fp-agent-stop {
|
|
267
285
|
margin-left: 8px;
|
|
268
286
|
align-self: center;
|
|
@@ -366,6 +384,85 @@
|
|
|
366
384
|
font-size: 16px;
|
|
367
385
|
}
|
|
368
386
|
|
|
387
|
+
/* Secondary/escape-hatch variant: transparent background, muted text.
|
|
388
|
+
Same hover glow as fp-chip-card so it reads as part of the same family
|
|
389
|
+
without competing visually with the primary action above it. */
|
|
390
|
+
.fp-chip-card.fp-chip-card-alt {
|
|
391
|
+
background: transparent;
|
|
392
|
+
border-color: #2a333c;
|
|
393
|
+
color: #8a96a3;
|
|
394
|
+
}
|
|
395
|
+
.fp-chip-card.fp-chip-card-alt .fp-chip-title {
|
|
396
|
+
color: #8a96a3;
|
|
397
|
+
font-weight: 500;
|
|
398
|
+
}
|
|
399
|
+
.fp-chip-card.fp-chip-card-alt:hover {
|
|
400
|
+
/* CLAUDE-031: this variant's background stays transparent at rest by
|
|
401
|
+
design, so on Node-RED's LIGHT theme it inherits a white/near-white
|
|
402
|
+
surrounding background — the near-white hover text below then had
|
|
403
|
+
nothing dark to sit on and became unreadable. A solid dark fill on
|
|
404
|
+
hover (paired with the same green glow as the primary chip) fixes
|
|
405
|
+
contrast regardless of the surrounding theme, without touching the
|
|
406
|
+
transparent, theme-following look at rest. */
|
|
407
|
+
background: #141a21;
|
|
408
|
+
border-color: #46d39a;
|
|
409
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1px #46d39a, 0 0 14px -2px #46d39a;
|
|
410
|
+
color: #dfe6ee;
|
|
411
|
+
}
|
|
412
|
+
.fp-chip-card.fp-chip-card-alt:hover .fp-chip-title {
|
|
413
|
+
color: #fff;
|
|
414
|
+
}
|
|
415
|
+
.fp-chip-card.fp-chip-card-alt .fp-chip-go {
|
|
416
|
+
color: #4a5662;
|
|
417
|
+
}
|
|
418
|
+
.fp-chip-card.fp-chip-card-alt:hover .fp-chip-go {
|
|
419
|
+
color: #46d39a;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* WS4 build consent gate (Proceed/Skip): sits inline in a question-row,
|
|
423
|
+
side by side, so it stays .fp-chip-card's compact pill-shaped sibling
|
|
424
|
+
rather than that pattern's full-width stacked card layout. Reuses the
|
|
425
|
+
same cockpit accent/muted color language so both read as one family. */
|
|
426
|
+
.fp-consent-chip {
|
|
427
|
+
display: inline-flex;
|
|
428
|
+
align-items: center;
|
|
429
|
+
padding: 6px 14px;
|
|
430
|
+
border-radius: 999px;
|
|
431
|
+
font-size: 12.5px;
|
|
432
|
+
font-weight: 600;
|
|
433
|
+
cursor: pointer;
|
|
434
|
+
white-space: nowrap;
|
|
435
|
+
background: #141a21;
|
|
436
|
+
border: 1px solid #2c3742;
|
|
437
|
+
color: #dfe6ee;
|
|
438
|
+
transition: border-color .12s ease, box-shadow .12s ease;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.fp-consent-chip:hover:not(:disabled) {
|
|
442
|
+
border-color: #46d39a;
|
|
443
|
+
box-shadow: 0 0 0 1px #46d39a, 0 0 10px -2px #46d39a;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.fp-consent-chip:active:not(:disabled) {
|
|
447
|
+
transform: translateY(1px);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.fp-consent-chip:disabled {
|
|
451
|
+
cursor: default;
|
|
452
|
+
opacity: 0.75;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.fp-consent-chip-primary {
|
|
456
|
+
border-color: rgba(70, 211, 154, 0.35);
|
|
457
|
+
color: #46d39a;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.fp-consent-chip-alt {
|
|
461
|
+
background: transparent;
|
|
462
|
+
border-color: #2a333c;
|
|
463
|
+
color: #8a96a3;
|
|
464
|
+
}
|
|
465
|
+
|
|
369
466
|
.fp-chip-hint {
|
|
370
467
|
margin-top: 4px;
|
|
371
468
|
font-size: 12px;
|
|
@@ -596,6 +693,63 @@
|
|
|
596
693
|
justify-content: flex-end;
|
|
597
694
|
}
|
|
598
695
|
|
|
696
|
+
/* W4 todo spine. Single-item plans render as a status line (.fp-todo-status);
|
|
697
|
+
multi-item plans render as a card (.fp-todo-card) with a checklist inside. */
|
|
698
|
+
.fp-todo-status {
|
|
699
|
+
display: inline-block;
|
|
700
|
+
font-size: 12px;
|
|
701
|
+
padding: 3px 10px;
|
|
702
|
+
margin: 0 0 4px 0;
|
|
703
|
+
border-radius: 12px;
|
|
704
|
+
max-width: 100%;
|
|
705
|
+
overflow: hidden;
|
|
706
|
+
text-overflow: ellipsis;
|
|
707
|
+
white-space: nowrap;
|
|
708
|
+
}
|
|
709
|
+
.fp-todo-pending, .fp-todo-active {
|
|
710
|
+
background: var(--red-ui-secondary-background, #eee);
|
|
711
|
+
color: var(--red-ui-secondary-text-color, #888);
|
|
712
|
+
}
|
|
713
|
+
.fp-todo-done {
|
|
714
|
+
background: rgba(34, 139, 34, 0.12);
|
|
715
|
+
color: #1a7a1a;
|
|
716
|
+
}
|
|
717
|
+
.fp-todo-failed {
|
|
718
|
+
background: rgba(200, 40, 40, 0.10);
|
|
719
|
+
color: #b22222;
|
|
720
|
+
}
|
|
721
|
+
.fp-todo-card {
|
|
722
|
+
padding: 6px 10px;
|
|
723
|
+
margin: 0 0 4px 0;
|
|
724
|
+
background: var(--red-ui-secondary-background, #eee);
|
|
725
|
+
border-radius: 6px;
|
|
726
|
+
font-size: 13px;
|
|
727
|
+
}
|
|
728
|
+
.fp-todo-list {
|
|
729
|
+
list-style: none;
|
|
730
|
+
padding: 0;
|
|
731
|
+
margin: 0;
|
|
732
|
+
}
|
|
733
|
+
.fp-todo-item {
|
|
734
|
+
padding: 1px 0;
|
|
735
|
+
line-height: 1.5;
|
|
736
|
+
}
|
|
737
|
+
.fp-todo-item-pending { color: var(--red-ui-secondary-text-color, #999); }
|
|
738
|
+
.fp-todo-item-active { font-weight: 600; color: var(--red-ui-text-color, #333); }
|
|
739
|
+
.fp-todo-item-done { color: #1a7a1a; }
|
|
740
|
+
.fp-todo-item-failed { color: #b22222; }
|
|
741
|
+
|
|
742
|
+
/* P10-D2: honest-interruption notice appended inside a "todo" record whose
|
|
743
|
+
last run event isn't "done" (see rerenderTodoRecord, modes.js). */
|
|
744
|
+
.fp-todo-interrupted {
|
|
745
|
+
margin-top: 6px;
|
|
746
|
+
padding: 4px 8px;
|
|
747
|
+
border-radius: 4px;
|
|
748
|
+
font-size: 12px;
|
|
749
|
+
background: rgba(200, 140, 0, 0.10);
|
|
750
|
+
color: #8a5a00;
|
|
751
|
+
}
|
|
752
|
+
|
|
599
753
|
.fp-json-toolbar {
|
|
600
754
|
display: flex;
|
|
601
755
|
justify-content: flex-end;
|