@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 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 any OpenAI-compatible API (OpenAI, LocalAI,
10
- Ollama, etc.) and helps you generate, modify, document, and discuss your
11
- flows — without ever acting behind your back.
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
  ![FlowPilot sidebar](https://github.com/manny-est/flowpilot/releases/download/v0.2.1/sidebar-chat-overview.png)
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, OpenAI-compatible REST. No
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 (example: LocalAI)
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 any **OpenAI-compatible** API OpenAI itself, LocalAI,
107
- Ollama (with its OpenAI-compatible endpoint), LM Studio, etc.
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. Fill in:
113
- - **Provider Name** — any label, e.g. `LocalAI` or `OpenAI`.
114
- - **Base URL** — e.g. `http://localhost:8080` or `https://api.openai.com`.
115
- If Node-RED is running in Docker, `localhost` refers to the *Node-RED
116
- container*, not the Docker host use the provider's container name, a
117
- Docker network alias, or a host IP (e.g. `http://172.17.0.1:8080`)
118
- instead.
119
- - **API Key** leave blank unless your provider requires one.
120
- - **Model** type a model name, or click **Refresh models** to fetch the
121
- provider's available models (via `GET /v1/models`) and pick from the
122
- list.
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
+ hostuse 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
  ![Provider settings: Base URL, API key, model, and temperature fields](https://github.com/manny-est/flowpilot/releases/download/v0.2.1/sidebar-settings-providers.png)
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
  ![A successful Pre-flight check reply in Chat](https://github.com/manny-est/flowpilot/releases/download/v0.2.1/preflight-success.png)
131
144
 
@@ -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
- position: relative;
53
- top: 2px;
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
- .fp-typing span:nth-child(2) { animation-delay: 0.18s; }
257
- .fp-typing span:nth-child(3) { animation-delay: 0.36s; }
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;