Every other page carries its primary action top right (New flow,
Add store) — the lone Material FAB bottom right broke the pattern
and sat far from the empty-state text asking for exactly that
action. The empty state now offers the button in place too.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- every daemon file row gets a copy-to-clipboard action next to
view/open so terminal users can grab the raw path
- audit stat subtitle says 'n of m events verified' instead of the
cryptic 'n/m chain'
- capability source-kind breakdown renders display names
(Bundle/MCP/System) instead of raw lowercase wire tokens
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
One-click installs showed no trust signal at all (top security
finding of the usertest panel). Every install path — store card,
detail sheet, and the flow list's quick fix — now routes through
one confirmation dialog showing what the hub actually knows
before download: origin store, version, license, maturity, and
required services/capabilities, plus the sandbox model and an
honest note that per-entry signature status is not in the store
index yet (verification happens hub-side at install). Widget
tests cover content and confirm/cancel semantics.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The icon-only rail forced first-time users to guess (usertest:
Senior, a11y, UX personas). Three changes:
- Nav tooltips appear instantly and carry the page shortcut
(Cmd+1..9, Ctrl on non-mac — Ctrl activators added); expanded
labels show the same hint. Explicit button semantics for
screen readers on every destination.
- A visible 'Search & commands' row above the footer opens the
existing Cmd+K palette, which nothing in the UI advertised.
- Settings -> Appearance gains 'Keep the navigation expanded':
pins the rail with permanent labels (persisted preference).
Footer strip and pillar toggle made overflow-safe for the
animating rail; responsive test scrolls the by-design scrollable
destinations list.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The Hub/Module/Flow cards explained the basics in the very
vocabulary they were supposed to introduce (Rust binary, WASM,
YAML, hash-chained). Each card now leads with a plain-language
explanation; the technical wording moved behind a per-card
'for the technically curious' toggle. DE and EN.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The empty state explained itself in operator jargon (detach,
detached.enabled, operator config) and offered no way forward.
Now it says what background runs are in everyday language and
opens the built-in guide — which carries the exact activation
steps — via a real button. DE and EN.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Wires the editor's new onPickFile host callback to file_picker
(withData: the editor receives name + bytes, never a raw path).
Pins chain_studio_flow_editor to v0.23.0. No more typing absolute
paths to feed a flow a file.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Stefan's live findings, all four addressed at the root:
- 'In 3 Fragen loslegen' read like ad copy → the entry is now plainly
'Einrichtung starten' / 'Start setup'.
- The setup button sat permanently on the Welcome page of a running
app ('setup after the app runs is backwards' — reported twice). A
fresh install now starts INSIDE the setup: SetupGateScreen hosts
the wizard embedded as the page (new embedded/onFinished modes on
GuidedSetupDialog), with an explicit 'Später einrichten' skip.
Welcome loses the setup button entirely and stays a calm intro.
- Re-running the setup later lives in Settings → General ('Run setup
again…'), the single post-first-run home.
- 'You must grant access first and only then see what will be done':
the preview used to spawn the chain CLI, whose first run could pop
the macOS permission prompt BEFORE the plan was ever shown. The
preview now calls the new PlanSetup RPC over the live hub
connection (no subprocess, nothing granted); the CLI remains only
a fallback when no hub is reachable — and applying stays the
explicit, separate step.
Widget tests: gate hosts the wizard + skip/cancel leave it; CLI-path
tests drive the fallback through the new hub-preview test seam.
Suite 76 green, analyze clean.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Accessibility/responsive audit pass with two new permanent test
gates (test/a11y_test.dart: WCAG text contrast + labeled tap
targets on every page in both themes; test/responsive_test.dart:
no layout overflow at 800/960/1280/1920 px). Findings fixed:
- Light theme primary/tertiary sky-500 → sky-700: white text on
the lighter accent only reached 2.8:1 (welcome CTA, active
sidebar label); sky-700 clears WCAG AA at ~5.9:1. Dark theme
unchanged (already compliant). FABs now follow the same accent
instead of Material 3's washed-out tonal default.
- Audit page: filter chips collapse into a checkmark popup menu
below 900 px window width (app bar overflowed); the live-status
bar's left text is now Expanded with ellipsis so the row can
shrink, and the disconnected state's copyable error gets the
full remaining width.
- German strings now use formal address consistently (~20 strings
still used du-forms next to Sie-forms on welcome/setup), the
audit event-type chip "Step" is "Schritt", and the doctor
page's event count pluralises correctly in both languages.
flutter analyze clean, 64 tests green. Screenshot pass light+dark
via the guide-shots harness (verified parity, no overflows).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Two settings bugs the operator hit:
1. 'Test connection' appeared to do nothing. The result/error panel
renders at the bottom of the System-AI editor's scrollable,
600px-capped form, so on a tall dialog it lands below the fold —
the footer button flickers 'Testing…' and nothing visible changes.
The editor now holds a ScrollController and animates the content
to reveal the outcome whenever a test result or error appears.
2. The welcome onboarding checklist kept 'connect System-AI'
unchecked right after saving a working config. The checklist row
opens the Settings dialog (an overlay, not a navigation), and on
close the checklist never re-probed — so it showed the stale
pre-config state. Both settings-opening rows (System-AI, MCP) now
re-probe when the dialog closes; navigation-based rows already
self-heal on return.
Studio suite green; flutter analyze clean.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Post-apply the wizard now renders real Studio actions instead of CLI
text: a start-hub button that polls until the daemon answers,
per-module install buttons (capability-name install via the hub's
store index) with done/progress states, and an open-the-starter-flow
button that navigates to the Flows page. 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 that re-assembles the plan (allow_unsigned_modules).
Fresh installs (no config, no setup-plan.yaml) auto-open the wizard
once per run — the wizard IS the onboarding — and it steps back once
a setup exists. The welcome CTA is framed honestly ('get started in
3 questions'), and after the wizard closes the onboarding checklist
remounts, re-probes, and says what the assistant already covered
(profile line from setup-plan.yaml) instead of acting as a second,
disconnected onboarding surface.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
New Runs sidebar destination listing detached invocations (detach:true)
with phase, current step, project and a Cancel button while
pending/running. Workspace-scoped like Audit/Approvals, polls every 2s.
Detached runs are opt-in (detached.enabled) — the empty state explains
how to enable them. Inline help doc DE+EN. DetachedRun model +
listDetachedRuns/cancelDetachedRun in HubService, backed by the SDK's
listInvocations()/cancelInvocation(). flutter analyze clean; 29 tests
green (sidebar Y-stability updated for the new destination, model
mapping unit-tested).
Screenshot verification (light+dark) deferred — shared desktop in use.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
FlowsPage passes the active workspace to the editor and switches the
workspace when the operator accepts a file-wins mismatch. Rebuilds the
chip live on workspace change. Editor package bumped to 0.22.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Multi-project stage 1 against the shared hub (platform design
docs/architecture/projects.md, § Studio):
- ChainWorkspaceSwitcher in the Audit + Approvals AppBars: lists the
registry (colour dot per project, shield for protected, honesty
tooltip), 'All projects' stays reachable — a filter, not a jail.
Selection is persisted and shared via the Workspace notifier.
- Audit page: list query AND live stream re-scoped hub-side on switch.
- Approvals page: pending + history scoped; the sidebar badge counts
the active workspace's pending approvals.
- Flow runs are stamped with the active workspace; a flow file
carrying its own project: keeps it (file wins, CLI semantics).
- Data layer: listProjects/ProjectRef; project fields on AuditEvent,
PendingApproval(+Record), SavedFlow; project params through
HubService. l10n DE+EN. Widget tests for the switcher contract.
Visual verification (light+dark screenshots) still pending — the
shared desktop was in active use; code paths are covered by
flutter test (26 green).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- approvals: empty/legacy hub prompts render the localized fallback;
approving without show: data asks for conscious confirmation first
- chain_log: write to ~/.chain/logs/studio-errors.log (was .fai),
one-time best-effort migration of the legacy file + rotation sibling
- l10n: 'manipulationssicher' -> 'manipulationserkennend', neutral
WORM-1 blurb, doctor pill 'Integritätskette v1', federation hint
says the CA authenticates the first connect (DE+EN)
- theme: muted text token now >=4.5:1 on canvas, cards and elevated
dark surfaces (was 3.7:1 on cards)
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The grouped store showed the hub's English category labels verbatim
(Documents, Data & Formats) even in German. Map the canonical slug to
DE/EN via l10n (storeCat*), and localize the Modules/Studio segment
(storeSegment*). Falls back to the hub label for an unknown slug.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The store grid was a flat jumble. It now renders labelled sections per
canonical category (App-Store style, fixed order, with counts), and a
top 'Modules | Studio & Themes' segment splits flow modules from Studio
plugins/themes. StoreItem carries the hub's canonical_category(+label);
falls back to the raw category label for a pre-0.21 hub.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The guided setup is the fastest path to a working first run, so lead
with a FilledButton instead of a low-emphasis outlined one (welcome
page). Delete pages/modules.dart — ModulesPage was never routed
(superseded by the Store 'Installed' filter) and nothing imports it;
flutter analyze stays clean.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
StoreItem gains source (mapped from StoreEntry.source); the store grid
shows a 'from <store>' label for operator-added stores (bundled seed
unlabelled). Foundation for grouping by store. EN+DE l10n.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The grid cell rendered a bare category glyph in a CircleAvatar; the detail
view uses _ModuleIcon (module icon URL with category fallback). Grid now
uses _ModuleIcon too — consistent, aligned, shows per-module icons.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
A Welcome 'Setup assistant' button opens a wizard that collects
scenario / intent / target (+ approval & data-local toggles), then calls
`chain init --answers` to preview the assembled plan and `--apply --force`
to write the config — reusing the Rust deterministic engine, no logic
duplicated. New SystemActions.chainInit; copyable errors via
showFaiProcessError; EN+DE l10n. analyze clean; smoke test + existing
welcome/sidebar tests pass.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The Audit page subscribes to streamEvents and nudges an immediate
(debounced) refresh on each new event, so the feed updates instantly
instead of waiting up to 2 s. Reuses the proven _refresh() path, so
list management + filtering + hash-chain ordering are unchanged. The
2 s poll remains the safety net: on a persistent stream error the page
is still fresh within the interval; a clean stream close re-subscribes
once after 3 s. Subscription + debounce cancelled on dispose.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The approval card only rendered the payload section when a preview
existed, so a step with no 'show:' showed nothing and the reviewer
could not tell why. Now always show the section: a present payload
scrolls inside a height-capped, copyable box; an absent one shows an
explanatory hint (the flow's approval step chooses what to surface via
its 'show:' field). Relabel 'data to be released' -> 'data to review'
(the payload is review context, accurate to its source).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Audit sweep after the System-AI fix: the Settings dialog rendered its
two _error states as a bare Text (hub-endpoint save, default-scope
edit), and the Audit live-status bar showed the raw load failure in a
non-selectable Text (the only place that failure surfaces — the
empty-state below shows just a generic hint). Route the Settings errors
through ChainErrorBox and make the Audit disconnected text a
SelectableText. Errors must always be clipboard-copyable.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- store: repair the filter dialog crash (a Spacer lived directly in
AlertDialog.actions, which is an OverflowBar, not a Flex — it threw
and rendered a broken dialog). Buttons now sit in a Row.
- store: promote the module-store manager from a bare icon to a
labelled 'Add store' button, and fully localize the dialog (DE/EN).
- store: add a curated 'Suggested stores' shelf with one-click
add/remove (first entry: Recl∆Im). Each suggestion is probed for
reachability and shows 'not available yet' until its index is
published, instead of failing only on click. Fail-open on network
errors so a transient hiccup never hides a real store.
- sidebar: the channel pill is now a one-click channel switcher
(menu with per-channel running state + active check; switching
writes ~/.chain/current-channel, restarts the daemon, and Studio
repoints to the new channel).
- approvals: lead the card with the human prompt ('what am I
releasing?') and demote the flow/step id to a metadata line; clear
fallback when the step left the prompt empty.
- welcome: tidy the docs grid into equal-height paired rows with a
full-width trailing card for the odd one out.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
A store icon in the Store app bar opens a dialog that lists the
configured module stores + the bundled seed (with per-source module
counts), lets the operator add a store by index URL (the hub fetches +
merges it live so its modules appear immediately), and remove a store.
Backed by the new ListStores/AddStore/RemoveStore RPCs + SDK methods.
This is how a domain app's published modules (e.g. reclaim's) become
visible in the Store without touching the CLI.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
From a live-test audit:
- Install via the flow-editor 'Fix' sent 'debug.echo@^0' (version
constraint included) as the install source; the hub resolves by bare
name so it missed ('no store entry for debug.echo@^0'). Strip the
@<constraint> like the Store page does — debug.echo now installs.
- Errors the operator could not copy: route the daemon-start failure
(its stderr!), the flow-editor install failure and the federation
issue failure through showFaiErrorSnack / a new showFaiProcessError
helper, so every error is selectable, one-tap copyable and logged.
- Diagnose page opened slowly because doctor() Future.wait-ed on a live
manifest fetch (8s server timeout); cap that one check at 2s so the
page no longer waits on the network.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The Studio design system, widgets and helpers carried a Fai* / fai_
prefix (FaiSpace, FaiColors, FaiTheme, FaiLog, 17 fai_*.dart files, the
faiBinary* l10n keys). Studio is the Ch∆In product, so rename them to
Chain* / chain_ — carefully preserving English fail/failure/failed.
Also fix stale references: the 'fai' binary in l10n strings -> 'chain',
FAI_* env vars (FAI_BIN/DATA_DIR/MODULES_DIR/TODAY/BOOTSTRAP_TOKEN) ->
CHAIN_*, fai_platform -> fai_chain, fai_hub -> chain_hub. Vendor
security-hook tooling (FAI_BANNED_TERMS_FILE) + the .fai bundle ext left.
flutter analyze + test: clean (20 passed).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Studio is the Ch∆In product's GUI, not a F∆I-vendor app. Rename the
Flutter package, all package: imports, and the build identity across
platforms: linux/windows CMake BINARY_NAME + project, Windows Runner.rc
fields, macOS PRODUCT_NAME / bundle id (ai.flemming.chain.chainStudio) /
.app + scheme BuildableName. Update the client-SDK + flow-editor deps to
their renamed chain_* packages (path + git URL). Company/copyright fields
now read Flemming.AI. flutter analyze: clean.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Track the platform rename: the hub spawn path is now ~/.chain/bin/chain
(was ~/.fai/bin/fai.exe on Windows — both dir and binary were stale, so
Studio could not launch the hub after the config-dir rename), the
~/.fai/* help strings become ~/.chain/*, FAI_REGISTRY_TOKEN ->
CHAIN_REGISTRY_TOKEN, and the two in-app doc URLs point at the public
fai/chain repo (fai/platform was renamed to the private fai/chain-private).
The .fai module bundle extension is left unchanged (format phase).
flutter analyze: no issues.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Studio follows the platform rename: product branding F∆I -> Ch∆In in UI
strings, command examples fai -> chain, and — critically — the spawned
hub binary path ~/.fai/bin/fai -> ~/.fai/bin/chain so Studio launches
the renamed binary. The fai_* Dart identifiers (FaiLog, widget files,
the generated SDK) stay = vendor/internal namespace. flutter analyze:
no issues.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The doc'd first install is debug.echo, but the Welcome onboarding
checklist only went green for a text.* capability — so a user
following the quickstart saw the box stay unchecked. Match any
non-system (non-built-in) capability instead.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
A new 'Föderation' destination (primary side) lists connected
satellites — name, region, version, wire version, advertised
capabilities — and adds them in one step: 'Add satellite' issues a
single-use bootstrap token bundled with the primary CA as a
ready-to-paste satellite config (the bundled CA makes the first
connect tamper-proof). Localized EN + DE, in-app help doc. Uses the
new HubService.listSatellites / issueSatelliteToken wrapping the
SDK's federation methods.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- Strip ANSI / control characters when reading log files so daemon
logs that carry colour escape codes render clean instead of as
garbled special characters (the source side is fixed in the hub
too; this is the defensive belt for existing files).
- Generalise the file viewer (read top-down + plain mode) and add an
in-Studio "View" affordance for config.yaml / .yml / .toml on the
Doctor paths panel, so config is readable without leaving Studio.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Brightness-aware elevation tokens (FaiElevation low/medium) applied
to cards, sheets and the sidebar active item; gentle hover-lift on
Store + Doc cards; a longer, eased sidebar expand using the
under-used FaiMotion.slow; and a branded empty state carrying the
F∆I delta mark with warmer spacing. Subtle, Linear/Raycast-style —
both light and dark themes tuned.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- Connection-aware Welcome: when the hub is down, show a hero with a
primary "Start hub" CTA + install fallback instead of a dead,
all-unchecked onboarding checklist (the first-run cliff).
- Actionable binary-not-found (file picker + install link, not a
"set FAI_BIN" dead end) and a connect-failure banner after
repeated failed health polls.
- Localize six hardcoded English error/toast clusters (DE+EN ARB).
- Bundle Inter + JetBrains Mono as assets; drop the runtime
google_fonts fetch (air-gap / KRITIS safe, no font-swap flash).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Three operator-UX gaps closed:
- Settings dialog's six-category sidebar (General / Appearance /
System AI / Integrations / Security / Maintenance) was
hardcoded English; now flows through AppLocalizations
("Allgemein" / "Darstellung" / "System-KI" / "Integrationen" /
"Sicherheit" / "Wartung"). Same for the per-panel title +
description.
- Per-channel daemon-action labels ('enable autostart' /
'disable autostart' / 'daemon restart' etc.) and the
OK / Failed result line in the toast also moved to l10n,
so the system-action feedback reads as one language.
- New 'Approvals' doc bundle (en + de) under assets/docs/,
registered as a fifth doc card on Welcome plus exposed via
the new public helper. The
Approvals, Audit and Doctor app-bars grow a Help icon button
next to Refresh that opens the matching doc in the existing
bottom-sheet reader — no extra screen, no learning curve.
Studio bumped to 0.67.0; editor path-override pulls in 0.20.1
(flow-list row polish).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The previous Add-source dialog was English-only and
operator-hostile — answered 'where do I install from?' without
explaining what a private module *is*. New version, DE + EN:
- Title + intro + button labels routed through AppLocalizations
("Modul-Quelle hinzufügen" / "Installation fehlgeschlagen"
instead of raw English strings).
- 'How private modules work' explainer block (3 sentences):
what a module is (`module.yaml` + WASM), how to package
it (`fai pack <dir>` → .fai bundle), where to host it
(any URL: own Forgejo / GitHub / S3), what verification the
hub does (sha256 + signature against trust store).
- Honest about the Studio gap: the dialog can install URLs +
packed bundles, but unpacked source directories still
require `fai install --link <path>` on the CLI. The
example command lives in its own code-style box, selectable.
- Layout: SingleChildScrollView'd so the explainer doesn't
push the buttons off short viewports.
Studio bumped to 0.66.0; editor path-override pulls in 0.20.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Two host-side pieces that complete the editor 0.18 quick-fix
loop:
- FlowsPage now fetches the store catalog (`searchStore` with
a 500-item ceiling) on open and hands it as `storeCapabilities`
to the FlowEditorPage. The editor's analyzer uses it to
decide whether an unknown-cap fix shows "Install …" or the
Add-source alternative.
- New `_AddModuleSourceDialog` — wired through the editor's
`onAddModuleSource` callback. Asks the operator for a URL
or local .fai bundle path; passes the value into
`HubService.installModule(source: …)`. Honest about its
limits: includes a card pointing the operator at
`fai install --link <path>` for unpacked module source
directories (which the gRPC install API doesn't currently
support — that's CLI-only).
Studio bumped to 0.65.0; editor path-override pulls in 0.18.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
FlowsPage now passes onInstallCapability to the editor — the
editor's 'Install <cap>' button on an unknown-capability
diagnostic calls HubService.installModule, refreshes the
capability list, and returns it so the editor reanalyzes and
clears the issue.
On install failure: friendly SnackBar surfaces the error. The
operator never gets stuck on the analyzer reporting a
capability they just clicked to install.
Studio bumped to 0.64.0; editor path-override pulls in 0.17.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Bundles the error-UX overhaul and the inline log viewer:
- New `FaiLog` (`~/.fai/logs/studio-errors.log`, 256 KiB rotation,
JSON-per-line). Every operator-visible failure is appended so
`fai admin doctor` and the new viewer can show the trail
without the operator having to reproduce the failure.
- New `showFaiErrorSnack` / `showFaiErrorDialog` helpers wrap
`FaiErrorBox` in copyable surfaces; 27 ad-hoc
`SnackBar(content: Text(e.toString()))` sites swept to use
them (settings, doctor, audit, store, module sheet, system-AI
editor, flow output).
- New `FaiLogViewer` modal (`showFaiLogViewer`) renders log
files inline with line numbers, JSON-key + `[level]` token
colouring, Copy-all, Refresh, Open-externally. Doctor's
daemon-paths panel grows a "View" button next to "Open" for
every `.log` row and now also lists the Studio errors log.
- Today carousel: CTAs now actually re-run search after a
`filterCategory` / `runQuery` story is tapped (was only
flipping the chip state). Fallback story list bumped to 8.
- Editor bumped to git ref carrying 0.15.0 (type-token
colouring + analyzer diagnostics).
Studio bumped to 0.62.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Two visible UX shifts:
1. Store Today carousel.
- Three hardcoded stories rewritten to be generic:
'Modules are the building blocks',
'Flows chain modules deterministically',
'Bring your own sources' — no DeepWiki / Semgrep /
text.extract / extract-summarize.yaml mentions. The
concrete brand suggestions live in Settings → MCP
Clients where the operator goes deliberately.
- +DeepWiki / +Semgrep quick-add chips removed from
the hero footer. They felt like ads on every page
load. The standalone Suggested Sources strip below
still picks them up, but the editorial hero stays
clean.
- Auto-hide the entire carousel once installedCount
≥ 3 — the operator has demonstrably been here
before; the welcome strip stops earning its scroll
cost.
2. Editor bump to 0.13.0:
- Edge selection (click a wire to select it)
- Properties panel edge-info mode with type-compat
indicator + Disconnect button
- Canvas-wide background tap closes the panel (works
even when zoomed out so the grid doesn't fill the
viewport)
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Three changes:
1. Onboarding checklist hints no longer mention DeepWiki,
Semgrep, text.extract, or extract-summarize.yaml by
name. Brand- and file-specific copy moved to neutral
feature pointers ('add an MCP source', 'install a
module'). Brand names belong on the welcome page only
if they're load-bearing for understanding, which they
aren't.
2. Checklist rows are now clickable. Tapping a row navigates
to the page where the operator can complete it — MCP +
AI open Settings, Module opens Store, Flow opens Flows.
StudioShellState gains a public navigateTo(pageId) helper
so descendants can drive sidebar selection without
plumbing a controller through props.
3. Theme picker hint copy rewritten. Old hint suggested
'Custom' was a single-colour tweak; new copy spells out
that Material 3 derives a full palette (primary,
secondary, tertiary, surface, …) from one seed colour.
The Custom tile shows a small tune icon so its
open-the-picker semantics is visually distinct from the
apply-immediately plugin tiles.
Editor bumped to 0.12.0 (panel toggle + LabVIEW-style port
colours).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Settings dialog's Theme Plugin section is now a grid of
swatched tiles:
- Built-in (none) — falls back to FaiTheme.light/.dark
- One tile per installed studio.theme.* plugin, each
showing the plugin's primary/secondary/tertiary as
live colour dots. Tile loads its preview lazily so a
dozen installed themes don't block the picker.
- Custom — opens a colour-picker dialog with 12 curated
Material presets + a hex input + live preview. Selecting
applies ColorScheme.fromSeed for both brightnesses.
main.dart's _pluginThemes parses a 'custom:#RRGGBB' sigil
in the same notifier slot as plugin capability ids, so the
existing persistence + restoration paths cover the custom
case with no new state.
Bumps editor to 0.11.0 (type-checked port connections +
dynamic card width fix + card-height border allowance) and
Studio to 0.58.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Picks up:
- fai_studio_flow_editor 0.9.0: per-field input + output
ports rendered from ModuleInfo, i18n tooltips, four
additional canvas patterns ported from jai_client.
- fai_client_sdk 0.18.0: regenerated ModuleField bindings
for the schema_version 3 / per-field-description proto
bump in fai/platform.
Wires StudioFlowRunDriver.moduleInfo so the editor can
fetch declared field info per step capability. The hub
maps schema_version 3 manifest fields (inputs/outputs
with description.en/de) through ModuleInfoResponse; this
patch wraps them back into the editor's ModuleSpec /
ModuleField vocabulary so the canvas paints them as
distinct anchors with hover tooltips.
ModuleDetail in hub.dart now carries the same inputs +
outputs lists (with ModuleFieldInfo type + i18n
description map), enabling other Studio surfaces — e.g.
the module-detail sheet — to render bilingual field docs
in a later pass.
Plus: store-doc nested-scroll fix. The module detail
panel's docs section sat inside its own 480px viewport
inside the outer sheet's SingleChildScrollView, producing
the double-scrollbar feel. Setting
physics: NeverScrollableScrollPhysics on the Markdown
widget and dropping the maxHeight lets the docs scroll
as part of the outer sheet — one scrollbar, predictable
mouse-wheel behaviour.
Bumps fai_studio to 0.56.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Welcome page used ConstrainedBox(maxWidth: 960) inside a
left-aligned Column, so on the 1440x900 default window
the content hugged the left edge and left ~370 px of
empty space on the right. With Stefan's M4 sidebar
collapsed to 72 px the asymmetry was the dominant visual
in the first thing every operator sees.
Wrap the ConstrainedBox in a Center widget. 960 px stays
an opinionated reading width — long-form prose gets
uncomfortable past ~1100 px — but the slack now splits
evenly so the content sits with ~190 px breathing room
on both sides instead of all on one.
Bumps the editor-package lock pointer to ad2e5b5 (same
0.2.2 version, picks up the extract-with-approval test
commit on top of f8138f3) as a side-effect of the
flutter pub upgrade run during verification.
Version 0.52.2 -> 0.52.3.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Studio's Flows destination is now the swappable
fai_studio_flow_editor's full surface: a drag-and-drop
graph view, the raw YAML text editor, and the run tab
with inputs form + live step progress + outputs.
What's gone:
- The old saved-flows list + per-row run dialog.
- The separate "flow-editor" navigation destination (one
icon, not two — operators reach the editor by clicking
Flows, period).
- _FlowEditorAdapter (no longer needed; FlowsPage hands
the runDriver to the editor directly).
What's new:
- lib/data/flow_run_driver.dart — StudioFlowRunDriver:
adapter implementing the editor's FlowRunDriver. Maps
runFlow() to HubService.runSavedFlow and events() to
HubService.streamEvents filtered to step.* event types.
Converts proto-shaped FlowOutput variants to the editor's
host-agnostic FlowOutputValue family.
- lib/pages/flows.dart — replaced with a 50-line wrapper
that loads capabilities into the editor's picker dropdown
and forwards the active locale.
Editor pinned to fai_studio_flow_editor 0.2.0 (commit
870cbc2). All editor state — file list, dirty tracking, tab
selection, graph layout sidecar, properties panel — lives in
the editor package now; Studio just supplies the hub bridge.
Version 0.51.10 -> 0.52.0 (minor bump — Flows-page contract
changed, separate flow-editor destination removed).
flutter analyze: 0 issues. flutter test: 12/12 green.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The flow-run dialog showed a single spinner + "running…" label
for the whole run. For multi-step flows the operator had no
way to see *which* step was busy or how close the run was to
finishing.
Replace the spinner with a live step list driven by a
StreamEvents subscription:
✔ extract 0.41s
⏳ summarize
◻ notify
━━━━━━━━━━──── 35%
Mirrors the `fai run` CLI rendering — one shared visual
language across both surfaces. Steps appear in execution
order as the hub emits step.started events; check + duration
on completion; cross + first-line error on failure; pause
icon on approval gates.
Implementation:
- HubService.streamEvents(backfill, types) — new public
stream-facade method that wraps HubClient.streamEvents and
maps proto LoggedEvent → AuditEvent for the rest of Studio.
Subscribed with backfill=0 so the dialog only sees events
from this very run.
- _FlowRunDialogState.initState subscribes BEFORE submitting
the run, so the first step.started never gets lost in the
gRPC handshake gap.
- Two-layer filter on incoming events: same flow name AND
timestamp >= dialog open time. The timestamp gate is what
stops a previous run's tail-end from painting stale rows
if the user re-runs the same saved flow.
- _LiveStep + _LiveStepList — insertion-ordered map renders
rows in runtime execution order (not alphabetical), so
what the operator sees matches what the hub did.
Version 0.51.5 → 0.51.6.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>