chain-studio/CHANGELOG.md
flemming-it 2f076ccf29
Some checks failed
Security / Security check (push) Failing after 1s
feat(store,doctor): surface the hub's trust + exposure data (0.77.0)
The trust-gate dialog replaces its generic 'no per-entry status yet
(alpha)' note with the hub's classified verification statement —
pinned store key / trusted publishers (green), installs without
signature checking (amber), install would be refused (red), bridge
entry (neutral) — via one shared describeInstallVerification mapping.
Against a pre-0.23 hub the field is empty and the old honest wording
stays (pinned by test).

Information architecture: policy-off is a GLOBAL fact, so it appears
as ONE ChainInlineHelp notice above the store grid instead of a
warning pill on every card (card noise); only 'blocked' — a genuine
per-source anomaly — earns a card pill. Doctor's host services show
the hub-classified network reach per endpoint (local only / private
network / publicly reachable with a protect-it hint / reach unknown).

Verified end-to-end against the live dev hub (guide harness): the
wire field arrives, the store page shows exactly one policy notice
and quiet cards; trust-gate variants captured via the dialog
harness. Suite 123 green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-21 13:14:13 +02:00

578 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
All notable changes to `chain_studio` recorded here. Pubspec
version + `kStudioVersion` in `lib/data/about_info.dart` stay in
lockstep.
## Unreleased
### Added — real trust + exposure data (0.77.0)
- **Per-entry install verification.** The hub now reports (since
0.23) how an install of each store entry would be verified under
the CURRENT policy — computed with the same resolvers the install
gate enforces, so display and enforcement cannot disagree. The
trust-gate dialog replaces its generic "no per-entry status yet
(alpha)" note with the classified statement: signature checked
via pinned store key / trusted publishers (green), installs
without signature checking (amber, policy off), install would be
refused (red), or bridge entry without a bundle signature. Store
cards stay quiet on the good path and wear an "unsigned"/
"blocked" warning pill only when installs are unverified —
same philosophy as the provenance pill. Against a pre-0.23 hub
everything keeps the old honest wording.
- **Service exposure on the doctor page.** Every declared host
service shows its network reach as classified by the hub from
the endpoint host (local only / private network / publicly
reachable / reach unknown — no DNS lookups). Publicly reachable
endpoints get the warning tone with a "make sure it is
protected" hint.
### Added — explain it where it happens (0.76.0)
- **In-place help pattern.** New `ChainInlineHelp` (a one-sentence
intro strip that says what a surface is and what will happen, with
an optional "Learn more" link into the doc sheet) and
`ChainFieldHelp` / `ChainFieldLabel` (a "?" affordance for a single
field). First applied to the add-satellite dialog, which used to
ask for a "name" with no hint of what a satellite even is
(usertest): it now leads with a plain explanation + a federation
"Learn more", and the name field carries a "?".
- **Page help opens the RIGHT topic.** The Federation and Runs help
buttons silently fell back to the architecture doc — `federation`
and `runs` had markdown assets but no catalog entry, so
`showFaiDoc` resolved them to the first doc. Both are registered
now; a new `doc_help_wiring_test.dart` asserts every
`showFaiDoc('slug')` call has a registered entry AND both locale
assets, so a help button can never open the wrong topic again.
### Security (0.75.0)
- **Sealed-area names are confidential by default.** The workspace
switcher no longer lists sealed areas by name on a casual glance
(names often carry client/mandate identity — usertest security
finding): it shows one aggregated row ("2 sealed areas") and
reveals the named rows only after a deliberate click, per menu
opening. Settings → Security offers "list sealed areas with
their names right away" for single-operator machines.
### Changed (0.75.0)
- **One segment control everywhere.** The same single-select
choice pattern used to appear as four different widgets: the
audit page's hover pills, the store's Material SegmentedButton
(Modules / Studio & Designs), the store filter dialog's
ChoiceChips and the approvals page's TabBar. All of them now use
the canonical `ChainSegments` pill control (the audit pattern
promoted to a shared widget, with icons and a11y semantics);
the approvals page keeps both lists alive in an IndexedStack so
switching does not refetch. A canon-guard test bans
TabBar/SegmentedButton/ChoiceChip from lib/ for good. Guide
images + wording updated (dark and light verified).
### Hardening round (test strategy, 2026-07-19)
- **Hermetic widget suites.** `HubService.instance` is injectable;
a scriptable fake (`test/support/fake_hub.dart`) answers every
member the pages touch and scripts per-RPC failures. The a11y and
responsive sweeps run against it — results no longer depend on
whether a hub happens to listen on the operator's machine (which
was the root of the historic a11y flake).
- **State-matrix sweep** (`state_matrix_test.dart`): every sidebar
page × hub condition (healthy / gone / too old / feature off) with
app-wide invariants — no "unreachable" claims while the hub
answers, no raw error text in the UI, classified states only.
- **Shared load-error view.** Store, Doctor, Audit, Approvals and
Federation no longer fold every load failure into "hub not
reachable"; `HubLoadErrorView` classifies into unreachable /
needs-newer-hub / load-failed-with-copyable-detail (new DE+EN
strings). Also fixed: the approvals page's hidden tab surfaced
load failures as uncaught async errors; the audit status bar
rendered the raw gRPC error wall instead of the friendly headline.
- **Version-skew gate.** `integration_test/skew_smoke_test.dart`
(run via the platform repo's `scripts/skew-smoke.sh`) boots the
released hub binary and walks every page with the same
invariants — the dev-Studio-against-old-hub combination is now a
release gate instead of a live-bug generator.
### Added (0.74.0)
- **Doctor findings deep-link to their page.** Summary tiles and
panel rows jump to where the finding is actioned: modules → store,
"approvals waiting for review" → approvals inbox, audit chain →
audit log (chevron affordance, tooltip + semantics button). The
host-services empty state gains a "view the configuration" button,
and the update banner's release-notes URL is a real link now.
### Fixed (0.74.0)
- **Runs page no longer contradicts the sidebar.** Load failures are
classified instead of all reading "hub not reachable": an older hub
without the ListInvocations RPC gets "this view needs a newer hub
version" with a doctor link, the detached-off refusal shows the
regular feature-off empty state, and unknown errors surface a
copyable detail box. "Not reachable" is reserved for genuine
connection failures.
- **Audit page timer leak.** The live-stream reconnect timer is held
and cancelled on dispose.
- **a11y suite flake killed at the root.** The pending-timer failures
came from the gRPC channel's 5-minute idle timer being armed when
the last stream closes; the suite now closes the channel and pumps
past the idle timeout (6 consecutive full runs green).
### Added
- **Full-history audit export.** The audit page's actions menu gains
"Export full log as JSONL" next to the current-view export: fetches
the complete event history of the active project scope (independent
of the type chip, the search field and the page's 100-event window)
and writes it as JSONL. The current-view export is unchanged; the
CLI `chain admin events --json` remains the canonical tool for
WORM-guaranteed exports (a stale code comment still advertised the
never-shipped `chain audit export` — fixed).
### Changed (usertest low-findings tail)
- **Honest hero badge.** The store hero wears "TODAY"/"HEUTE" only
for an operator-accepted story; the compiled-in fallback deck has
no date binding and now says "FEATURED"/"EMPFOHLEN".
- **Audit filter chips in UI type.** The Alle/Flow/Schritt/Modul
chips drop the monospace styling — mono stays reserved for paths
and identifiers.
- **One verb for the chain check (DE).** "Hash-Kette geprüft" is the
confirmation everywhere (audit header, doctor pill); "intakt"
remains the state headline. English was already consistent.
- **Readable sealed-area status.** The "stopped" label in the
workspace switcher gets a modest contrast bump.
### Changed (usertest panel 2026-07-17, 14 personas — all confirmed findings)
- **Install trust gate.** One confirmation dialog before every module
install (store card, detail sheet, flow quick-fix): source, version,
license, maturity, required services — plus an honest signature note
(the hub does not report per-entry signature status yet; no fake
badge).
- **Settings → About.** Product, Studio + hub version (live), vendor
Flemming.AI / Dr. Stefan Flemming, Apache 2.0, contact, docs link —
every value copyable.
- **Discoverable sidebar.** Instant tooltips with the ⌘19/^19
shortcut, semantics labels, a visible "Search & commands ⌘K" row,
and a setting to keep the rail always expanded.
- **Plain-language empty states.** Runs page explains background runs
in plain words and — via the hub's new `detached_enabled` flag —
says truthfully whether the feature is off or simply unused;
approvals inbox explains human approvals without raw capability
syntax; welcome cards lead with everyday language (tech detail
behind a toggle).
- **One term per concept.** "Fähigkeiten" is the German lead term
(welcome, integrations, federation); "Registrierungs-Token" instead
of "Enrollment-Token"; category and source-kind labels localized
(no lowercase wire tokens like `document`, `1 system`).
- **Audit page.** Free-text search over the event list; JSONL export
of the current view; the dev-only clear action moved from a bare
trash icon into a labeled overflow menu.
- **Doctor page.** Copy button on every daemon path row; "n of m
events verified" instead of "n/m chain"; hash-chain wording unified.
The module tile no longer counts the built-in `system`
pseudo-module (a fresh hub shows 0 modules, matching the welcome
checklist); the daemon-files panel warns when the audit DB lives in
an OS-cleanable temp directory; the daemon card states endpoint,
transport security, and token status (length only) in one line.
- **Federation page.** Primary action in the app bar and in the empty
state (FAB removed); plain-language empty text.
- **Store.** License pill on the module card; maturity pills explain
themselves on hover; carousel shows a textual position; German tab
says "Studio & Designs".
- **Formal address guard.** A test now rejects informal German forms
including reader-addressed imperatives; literal markdown backticks
are gone from both catalogs.
- **Setup.** The wizard replaces the Settings dialog instead of
stacking on it, with a stronger scrim; the try-out profile names
the upgrade path to a regulated profile.
- **Welcome checklist.** The "start a saved flow" tick is sticky
instead of silently unticking once the event leaves the
recent-events window.
### Changed (setup lives before the app)
- **First-run gate.** A fresh install starts inside the setup: a
dedicated screen hosts the wizard before the app appears (embedded
mode + explicit "Später einrichten" skip). The Welcome page loses
its setup button entirely; re-running the setup lives in Settings →
General ("Run setup again…"). Wording de-ad-ified: "Einrichtung
starten" instead of "In 3 Fragen loslegen".
- **Preview before permission.** The plan preview now calls the new
PlanSetup RPC over the live hub connection instead of spawning the
chain CLI — whose first run could pop the macOS file-access prompt
BEFORE the operator ever saw the plan. CLI remains the no-hub
fallback; applying stays the explicit separate step.
- **Native file dialog for flow file inputs** (with flow-editor
v0.23.0): the Run tab's file inputs open a real picker; typing an
absolute path is now only the no-host fallback.
### Fixed (startup + build time)
- **Black window on launch.** A corrupt preference value (`hub.secure`
stored as int `0` by an external `defaults write`) made
`SharedPreferences.getBool` throw inside `main()` before the first
frame — the app sat as a black window with no visible error. Pref
reads now tolerate wrong types (int coerces to bool, garbage falls
back to the default), and every pre-frame restore step is
failure-isolated so nothing can prevent `runApp` again. Regression
tests reproduce the corrupt store.
- **CocoaPods integration removed** (macOS). The project builds via
Swift Package Manager; the leftover Pods wiring (Podfile, `[CP]`
script phases, Pods framework refs, xcconfig includes) made every
build run both dependency managers — exactly what Flutter's
own "will improve the project's build time" warning was about.
### Added
- **Settings → Security shows the hub's auth policy.** New panel
backed by the hub's read-only `AuthStatus` RPC: active token
validator (static / JWT-RS256 with issuer, audience and JWKS
source), anonymous-access warning, and per-token cards with
scope grants, env-var presence and rate limits — T4/T5 security
administration finally visible outside YAML. Non-admin tokens
get a localized denied story instead of an error.
- **Permanent accessibility + responsive test gates.** Every page
must pass WCAG text contrast and labeled-tap-target guidelines
in both themes (`test/a11y_test.dart`) and lay out without
overflow from 800 to 1920 px (`test/responsive_test.dart`).
### Fixed
- **Daemon start with a wrong token no longer misreports.** Both
start paths (welcome CTA, sidebar) treated an auth-rejected hub
as "daemon dead" and showed a start-failure dialog while the
banner above correctly blamed the token; an auth rejection now
counts as "daemon alive".
- **Token fixed outside Studio heals the connection.** On an
auth-rejected poll the shell re-reads `~/.chain/hub-auth-token`
and reconnects when the file changed — following the banner's
own advice no longer requires re-saving in Settings or a
restart. An endpoint switch also resets the failure streak, so
a stale in-flight probe can't blame the new endpoint.
- **Security panel stays fresh.** The auth-policy view re-queries
after saving or clearing the hub token in the panel above, and
renders the hub's new `reload_required` flag as a plain-language
pending-reload warning (DE+EN).
- **Auth-rejected hub no longer reported as "unreachable".** With
token auth active, a wrong or rotated token got UNAUTHENTICATED
from a perfectly reachable hub, but the sustained-failure banner
said "can't reach the hub" — pointing the operator at the
endpoint instead of the token. The shell now probes with the
SDK's failure-kind-aware `probe()` and switches the banner to
"rejected the sign-in — check the access token" (key-off icon).
- **Light theme accent was below WCAG contrast.** Filled buttons
and the active sidebar label rendered white-on-sky-500 (2.8:1);
the light scheme now uses sky-700 (~5.9:1). FABs follow the
same accent instead of Material 3's tonal default.
- **Audit page at narrow window widths.** The app-bar filter chips
collapse into a checkmark menu below 900 px, and the live-status
bar shrinks gracefully (copyable disconnect error gets the full
row width).
- **Consistent formal address in German.** ~20 strings still used
du-forms next to the Sie-forms on welcome/setup; the audit
event-type chip "Step" is now "Schritt"; the doctor page's event
count pluralises correctly ("1 Ereignis") in both languages.
- **Stored tokens reached the wrong directory.** `~/.fai/` rename
leftovers: the hub-auth token and registry token were read from /
written to `~/.fai/` while the hub reads `~/.chain/` — a stored
registry token never reached the hub. Today-stories and UI texts
still advertising the retired `.fai` bundle extension fixed too.
### Fixed (wizard live-run findings 2026-07-14)
Field test of the setup wizard surfaced three trust breaks in one
run; all were reproduced against a stale CLI and fixed:
- **Errors surfaced behind the wizard.** `chain init` failures were
shown as a SnackBar, which lands BEHIND the wizard's modal barrier:
dimmed, clipped, its copy button unreachable — and the operator's
click at it hit the barrier, which (dismissible by default) closed
the whole wizard with all answers. Now: failures open a modal error
dialog ABOVE the wizard (copy button works, verbatim CLI output
behind "Details"), and the wizard is no longer barrier-dismissible —
leaving it is explicit via Abbrechen/Zurück.
- **CLI version skew explained.** When the resolved `chain` binary is
older than Studio and rejects `--plan-json`, the wizard now names
the skew in plain language — which binary was executed, that it
predates the assistant, and the update path — instead of leaking a
raw clap usage error. A missing binary gets the same treatment plus
a hint on step 3 before anything runs.
- **macOS folder prompt pre-explained.** Step 3 now states which
`chain` binary the preview will execute; when that binary physically
lives (symlinks resolved) in a TCC-protected folder (Documents/
Desktop/Downloads), the wizard says up front that macOS may ask for
folder access — instead of a bare permission prompt appearing in
the middle of setup.
- `FriendlyError` values now pass through `friendlyError()` unchanged
so call sites can route precise, localized stories through the
shared error presentation; `SystemActions` gained a public
`resolvedChainBinary()` and test seams for the run/resolve paths.
### Added (guided setup on grade-1 — steps A4/A5/B1 + doc automation)
- **Clickable next steps.** After apply, the wizard renders real
Studio actions instead of CLI text: start-hub button (polls until
the daemon answers), per-module install buttons with progress/done
states (capability-name install via the hub's store index), and an
open-the-starter-flow button navigating to Flows.
- **Signature dead end resolved.** Regulated plans explain in plain
language that modules come from a signed source; the preview offers
"allow installing from the public store" as one deliberate,
reversible switch (`allow_unsigned_modules`) that re-assembles the
plan. Air-gapped plans point to the offline-bundle path instead.
- **Fresh-install auto-open + honest framing.** On a fresh hub (no
config, no `setup-plan.yaml`) the wizard opens by itself, once per
run; the welcome CTA is now "In 3 Fragen loslegen" / "Get started
in 3 questions". After the wizard closes, the onboarding checklist
re-probes and states what the assistant already covered (applied
profile from `setup-plan.yaml`).
- **Free-text AI path (phase 1.2).** "Or just describe what you want
to do": the goal goes to the configured system AI, the reply is
validated against strict enum whitelists and comes back as an
editable "this is how I read your task" reflection feeding the same
preview/apply. Privacy line states local vs. provider processing;
without a system AI the menu path stands alone.
- **Nav manifest guard.** `test/nav_manifest_test.dart` generates
`docs/nav.generated.json` from the sidebar truth (ids, order = Cmd
numbers, DE+EN labels); the platform repo checks the operator guide
against the mirrored copy.
- **Guide screenshot harness.** `integration_test/guide_shots_test.dart`
boots a hermetic hub, seeds demo projects, walks every nav page,
the workspace switcher and the setup wizard, and writes the guide
PNGs — driven by the platform repo's `scripts/regen-studio-guide.sh`.
- **Fixed:** the integration-test hub fixture still looked for the
pre-rename `fai` binary and `chain_platform/` path, so its tests
silently skipped since the rename; it now resolves `$CHAIN_BIN`,
`chain` on PATH, and `../fai_chain/target/{release,debug}/chain`.
### Added (guided setup — persona re-audit fixes, grade-1 round)
- **Regulated path finishes without a terminal.** The post-apply
signed-source state now offers "Add a signed source…" (the stores
dialog with its pin-a-key field) plus the per-module install
buttons, instead of a hint with no affordance; a plain-language
trust hint explains why pinning the publisher's key matters.
- **Apply warnings surface.** Warning lines from `chain init --apply`
(e.g. the empty-trusted-publishers caveat) are shown selectable in
the done state instead of being swallowed on success.
- **Truthful preview.** New plan lines state which machine is being
set up (server/container targets configure THIS machine — said
explicitly), that regulated profiles get the hash-chained audit
log even when WORM is off, and that a curated reading list is
stored with the setup record.
- **Language pass.** Onboarding checklist switched to Sie-form and
"System-KI" (was du-form + "System-AI" next to the formal wizard);
"Audit-Sperre" jargon replaced with "Schreibschutz für das
Prüfprotokoll"; answers file now lives in a private per-dialog
temp dir instead of a fixed world-readable name.
### Added (multi-project, stage ③ — sealed areas)
- **Sealed-area connection switch.** The workspace switcher now lists
the operator's sealed areas (read from `~/.chain/sealed/` manifests,
the same source the CLI uses) below the shared projects, each with a
lock icon and a running/stopped status. Selecting one is a real
connection switch: Studio reconnects its hub client to the area's own
port with a full state reload — one window, one truth. A stopped area
is started first (`chain project start`) with a visible notice; a
failure surfaces as a copyable error and rolls back to the shared hub.
- **Identity bar.** While connected to a sealed area, a strip under the
AppBar is painted in the area's accent colour and names it, with a
one-click *Leave* back to the shared hub. The area colour is marking,
not theming — Studio's blue stays the app accent. (The window-title
tint is a small follow-up; the identity bar is the primary signal.)
- Selecting a shared project or "All projects" from inside a sealed area
switches the connection back to the shared hub first. The sealed
connection is never persisted across restarts — Studio always launches
on the shared hub and the operator re-enters an area deliberately.
### Added (detached-runs monitor — T3 parity)
- **Runs page.** A new sidebar destination lists detached invocations
(submitted with `detach: true`) with their phase, current step,
project and a **Cancel** button while pending/running. Workspace-
scoped like Audit and Approvals; polls every 2 s. Detached runs are
opt-in (`detached.enabled`), so the empty state explains how to turn
them on. Inline help doc (DE+EN). Backed by the SDK's
`listInvocations()` + `cancelInvocation()`.
### Added (multi-project, stages ① + ②)
- **Workspace switcher.** The Audit and Approvals AppBars carry a
workspace control listing the hub's project registry (colour dot per
project, a shield for `protected`, an honesty tooltip). "All projects"
stays reachable — a filter, not a jail. The selection is persisted and
shared across pages; it re-scopes the audit list AND live stream
hub-side, scopes approvals (pending + history), and drives the sidebar
approval badge. Runs launched from the editor are stamped with the
active workspace — unless the flow file declares its own `project:`,
in which case the file wins (CLI semantics).
- **Editor project chip + file-wins guard.** A flow file's own
`project:` shows as a chip; on mismatch with the active workspace an
amber pill offers a one-click switch (the file still wins for the run).
Backed by editor package 0.22.0.
### Fixed (usertest 2026-07-10 findings)
- **Approval prompts localize.** An approval whose flow step gave no
`prompt:` (and legacy rows carrying the hub's old baked-in English
sentence) now renders the localized fallback "Freigabe für diesen
Schritt erforderlich" / "Approval required for this step" — no more
English inside the German approvals UI.
- **Approving without review data asks first.** When the approval step
attached no `show:` payload, "Freigeben" opens a calm confirmation
("Ohne Prüfdaten freigeben?") explaining that the flow deliberately
attached no data, with an explicit "Trotzdem freigeben".
- **Studio error log moved to `~/.chain/logs/`.** Writes went to the
pre-rename `~/.fai/logs/studio-errors.log` while the Doctor page and
`chain doctor` read `~/.chain/…`. Studio now writes to `.chain` and
migrates the old file (+ rotation sibling) over once.
- **Honest audit wording (legal review).** DE strings no longer claim
"manipulationssicher" — the audit log is *manipulationserkennend*
(tamper-evident); "warum WORM-1 für KRITIS reicht" became a neutral
what-it-does-and-does-not sentence (EN too); the Doctor chain pill
says "Integritätskette v1" instead of "WORM-1"; the federation
enrollment hint says the CA *authenticates* the first connect.
- **WCAG-AA secondary text on dark.** De-emphasised text was 3.7:1 on
cards; the muted token is now ≥ 4.5:1 against canvas, cards and
elevated surfaces.
### Added
- **Live audit feed.** The Audit page subscribes to `streamEvents` and
refreshes instantly on each new event (debounced); the 2 s poll stays
as the safety net and re-subscribes after a clean stream close.
- **Channel switcher in the sidebar.** The active-channel pill (and the
collapsed chip) is now click-to-switch: a menu of every channel with
its running state + a check on the active one; switching writes
`~/.chain/current-channel`, restarts that channel's daemon, and Studio
repoints to it.
- **Module-store manager is prominent + bilingual.** The store page
gains a labelled "Add store" button (was a bare icon) opening a fully
localized dialog: configured stores, a curated **Suggested stores**
shelf with one-click add/remove (probed for reachability — shows "not
available yet" until a store's index is published), and an optional
per-store **pinned public key** field.
- **Approval payload clarity.** The approval card always shows the
payload section: a present payload scrolls inside a height-capped
copyable box; an absent one explains that the flow's approval step
chooses what to surface via its `show:` field.
### Fixed
- **Errors are copyable everywhere.** System-AI test-connection, the
Settings dialog, and the Audit status bar rendered failures as
non-copyable text; all now route through `ChainErrorBox` /
`SelectableText`.
- **Filter dialog crash** on the store page — a `Spacer` inside
`AlertDialog.actions` (an `OverflowBar`, not a Flex) threw; the
buttons now sit in a `Row`.
- **Welcome docs grid** tidied into equal-height paired rows.
- **Approval card** leads with the human prompt; the `flow step` id is
demoted to a metadata line.
- **Pulsing sidebar connection dot** restored when connected.
## 0.70.0 — 2026-06-13
### Added
- **Federation panel.** A new "Föderation" destination shows the
satellites connected to this hub (name, region, version, wire
version, advertised capabilities) and adds them in one step: press
**Add satellite**, name it, and the hub issues a single-use
bootstrap token bundled with its CA as a ready-to-paste satellite
config — the bundled CA makes the satellite's first connect
tamper-proof. Localized (EN + DE) with an in-app help doc. Backed
by new `HubClient.listSatellites` / `issueBootstrapToken` in the
Dart SDK.
## 0.68.0 — 2026-06-09
### Added
- **Inline approval driver**. `StudioFlowRunDriver` implements
the three new methods the editor 0.21.0 introduced
(`pendingApprovalIdForStep`, `approveApproval`,
`rejectApproval`) — all delegate to the existing
`HubService` approvals RPCs. End result: the Run tab now
hosts a complete Approve / Reject form inline, removing the
tab-switch detour to the standalone Approvals page.
## 0.67.0 — 2026-06-09
### Added
- **Inline help icons** in the Approvals, Audit, and Doctor
app-bars open the matching bundled doc in the existing
bottom-sheet reader via the new public helper
`showFaiDoc(BuildContext, slug)` exported from `welcome.dart`.
- **New `assets/docs/approvals.md`** (+ `_de.md`) explains the
approval concept end-to-end with a YAML example.
- **friendlyError hub-pattern matching**. Six hub-specific
failure shapes (approval rejected / timed out, output too
large, host service not declared, missing value reference,
MCP unreachable) get specific localised headlines + hints
before falling through to the gRPC-code default. Five new
test cases pin the matchers.
### Changed
- **Settings dialog sidebar fully localised** (Allgemein /
Darstellung / System-KI / Integrationen / Sicherheit /
Wartung). Per-panel titles + descriptions also.
- **Daemon action labels localised**: `enable autostart`,
`disable autostart`, restart / start / stop / status + the
OK / Failed result line.
## 0.66.0 — 2026-06-08
### Added
- **Add-module-source dialog** for private modules that
aren't in the public store. Asks for URL or local `.fai`
bundle path; carries an explainer block + `chain install --link`
example.
- **Store catalogue** passed to the flow editor so the
analyzer can decide between Install (in store) and Add
source (not in store).
## 0.65.x
- Editor 0.18.0 pickup; analyzer-error block on Run;
diagnostic strip persistence across tabs.
## 0.64.0 — 2026-06-08
### Added
- **Flow editor quick-fix install handler**.
`_onInstallCapability` wires the editor's "Install <cap>"
button to `HubService.installModule` and refreshes the
capability list on success.
## 0.63.0 — 2026-06-04
### Changed
- **Settings dialog refactored** from one 800-line vertical
scroll into a macOS-style sidebar with six categories.
## 0.62.x — 2026-06-03
### Added
- **`FaiLog` + central error helpers** (`showFaiErrorSnack`,
`showFaiErrorDialog`).
- **Inline `FaiLogViewer`** modal for tail-viewing log files.
- **Today CTAs** in the Store carousel actually re-run search
after a `filterCategory` / `runQuery` story.
## 0.61.x and earlier
See git log.