The regulated setup path sends the operator to the stores dialog to
pin a publisher key — but the field was labelled 'Angepinnter
Public-Key — PEM (optional)' with du-form developer prose (PEM,
vendor key) at exactly the trust-critical moment. Field now reads
'Signatur-Schlüssel anheften (PEM, optional)' with a plain-language
Sie-form explanation of what pinning does; the dialog intro and the
onboarding checklist follow (MCP jargon explained in the sentence,
developer-only follow-up cards labelled as such).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
- Regulated path finishes without a terminal: the signed-source
state offers 'Add a signed source…' (stores dialog with pin-a-key)
plus the per-module install buttons and a plain-language hint why
pinning the publisher's key matters — instead of a hint with no
affordance.
- Apply warnings (e.g. the empty-trusted-publishers caveat) surface
selectable in the done state instead of being swallowed.
- Truthful preview: new lines state which machine is being set up
(server/container targets configure THIS machine), that regulated
profiles always get the hash-chained audit log (even with WORM
off), and that the curated reading list is stored with the setup
record.
- Language pass: onboarding checklist in Sie-form + 'System-KI'
(was du-form + 'System-AI'), 'Audit-Sperre' jargon replaced,
answers file moved to a private per-dialog temp dir.
- Screenshot harness: GUIDE_SHOTS_THEME=light for light-parity
proof runs.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
integration_test/guide_shots_test.dart boots a hermetic hub
(HubFixture), seeds demo projects (open Bürgeramt; sealed
Ratsinformation and a setup.applied audit event only when the
runner confirms an isolated $HOME), launches the app in German +
dark mode, walks every sidebar page in Cmd order with
content-aware waits, opens the workspace switcher and the setup
wizard, and writes the guide PNGs via a driverless RepaintBoundary
capture. Driven by the platform repo's scripts/regen-studio-guide.sh.
Also fixes the hub fixture's binary resolution, dead since the
rename (it looked for 'fai' and ../chain_platform/): now $CHAIN_BIN,
'chain' on PATH, then ../fai_chain/target/{release,debug}/chain —
the integration tests actually run again instead of silently
skipping.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
test/nav_manifest_test.dart derives docs/nav.generated.json from
the _pages list (order = Cmd numbers), the labelOf switch, and both
.arb files. On any nav change it regenerates the manifest and fails
once with instructions to commit + mirror it to
fai_chain/docs/studio/, where the platform repo's docs_consistency
gate checks the operator guide against it — cross-repo nav drift
becomes a red gate instead of quietly rotting docs.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The wizard's first step now offers 'or just describe what you want
to do': the goal goes to the configured system AI, which maps it
onto the menu answers (validated against strict enum whitelists —
a hallucinated value can never reach the engine). The suggestion
comes back as an editable plain-language reflection ('this is how I
read your task') the operator can adjust step-by-step or take to
the same preview/apply the menu path uses. Trust rules per
guided-setup.md: suggestion only (never auto-apply), a privacy line
states whether the description is processed locally or sent to a
provider, and without a configured system AI the section explains
that the menu always works — no dead end.
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>
Reworks the Setup-Assistent toward the zero-learning-curve bar
(docs/architecture/guided-setup.md, phase 1.1):
- Every scenario/intent/target choice is now a localized option CARD
with a one-line plain-language explanation of what it configures
(DE+EN, Sie-form) — replacing the bare dropdowns whose labels were
English enum humanizations ('Regulated Production', 'This Laptop').
- Three explained steps with a 'Schritt n von 3' progress line
(stakes → task → environment); the two adaptive toggles move to the
last step in plain language (no 'air-gapped' jargon).
- The review step renders a localized PLAIN-LANGUAGE summary built
from 'chain init --answers --plan-json' (the structured SetupPlan) —
'Ch∆In richtet einen regulierten Betrieb ein: signierte Module
verlangt · … · geändert wird nur ~/.chain/config.yaml' — instead of
echoing the CLI's English prose. Warns when an existing config will
be overwritten. After apply: a plain 'Fertig' + next steps.
flutter analyze clean; widget tests for the step flow + German option
labels. Remaining per plan: clickable follow-up actions, signature
dead-end fix, placement/auto-open, and the LLM free-text path.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Reproducible CI (override-free) builds; an editor push can no longer
change what a Studio release builds against. The local path override
still wins for dev builds.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
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.
While in a sealed area an identity bar 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. Selecting a shared project from inside an area
switches the connection back first. The sealed connection is never
persisted across restarts.
New: SealedAreaService (manifest + PID discovery), Workspace sealed
switch logic, ChainSealedIdentityBar, SystemActions.chainProjectStart.
l10n DE+EN. flutter analyze clean; 33 tests green (switcher lists sealed
with lock+status, pill shows active area, identity bar renders in the
area colour). Runtime plumbing (discovery, start, endpoint, reach)
verified headlessly against real sealed instances under a redirected
HOME; the identity-bar screenshot is deferred (display click-automation
failed after sleep on the shared desktop — an environment issue, not a
code gap; the visible components are widget-tested).
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 welcome hero subtitle described Ch∆In as 'AI-assisted document
processing' / 'KI-gestützte Dokumentenverarbeitung' — too narrow. The
canonical product line is 'AI-assisted data processing' (flows also
handle streams and general data, not only documents). Fixed in both
locales (arb + generated app_localizations).
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>
Opening the channel switcher let the hover-exit collapse the rail at the
same moment, leaving the menu floating at the pill's old (expanded)
position. The pill now signals open/close; the sidebar suppresses its
collapse (_menuOpen) while the menu is up, so it stays aligned.
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>
friendlyError now pattern-matches module-download failures ('download
failed: ...') and renders a clear, copyable headline + the URL/status
detail, instead of letting the gRPC-Unavailable default show the generic
'hub not reachable' banner. EN+DE l10n.
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>
Adds a widget test asserting each destination icon keeps its Y position
whether the rail is collapsed or expanded — a recurring regression. To
drive expansion without a hover gesture (which trips RenderFlex overflow
mid-transition), a test-only startSidebarExpanded flag threads
StudioApp -> StudioShell -> _Sidebar (controller starts at 1.0, hover
disabled); _SidebarItems get stable ValueKeys. analyze clean; new test
and the existing smoke test pass.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Studio's Start-hub looked for 'fai' on PATH; post-rename the entry
binary is 'chain', so a fresh install failed to start the daemon.
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 module-store manager's 'Add a store' form gains an optional PEM
public-key field; when set it pins that publisher key to the store
(per-store signing trust). Localized DE/EN.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The collapsed connection dot was a static Container after the sidebar
refactor; route it through the shared ChainStatusDot with pulsing tied
to the connected state — a living live-signal, steady when down or
unknown.
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>
The System-AI editor rendered its failure (test connection, save, model
pull) as a bare Text(_error) — selectable-but-not-copyable, the exact
thing the operator needs to paste back. Route it through ChainErrorBox
(selectable + one-tap copy button), and show a failed test result via
ChainErrorBox too instead of a plain SelectableText.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
Use the raw store-index file in the public chain-modules/reclaim repo
(git.flemming.ai/chain-modules/reclaim/raw/branch/main/store.yaml) —
stable, no release-tag churn, fetched by the hub's StoreIndex::from_url.
The availability probe flips the row to 'Add' automatically once reclaim
publishes the file.
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>
'Tap to start' on an already-running hub reported 'daemon could not be
started' (the start failed because it was already up) then flashed the
error away as a SnackBar — confusing next to the sidebar's 'connected'.
Now: on a failed start, probe the hub; if it answers, just connect (no
false error). If it is genuinely down, show the daemon's stderr in a
persistent, copyable dialog (showFaiProcessErrorDialog) instead of a
SnackBar that vanishes before the operator can read or copy it.
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>
Studio defaulted its endpoint to the local channel's port (:50051), but
a curl|sh user is on the production channel (:50071) — so the sidebar
probed a different daemon than the Diagnose page reported, showing
'connected' next to 'production daemon stopped'. On first run Studio now
reads ~/.chain/current-channel (+ run/<ch>.endpoint) and follows the
active channel; an explicit Settings endpoint still wins and persists,
auto-discovery does not (re-follows the channel each launch). The
connection caption now names the channel ('Connected · production') so
it can never look contradictory again.
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 active-channel pill coloured 'production' with the theme error
colour — red read as 'something is broken'. Use ChainColors.success
(live & healthy) instead; still visibly distinct from beta (amber),
dev (accent) and local (grey).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
The release build aborted at the Xcode CodeSign step (no Developer-ID
identity), leaving an incomplete .app missing Contents/Frameworks —
which DYLD-crashed at launch ('Library not loaded: FlutterMacOS.framework').
Set CODE_SIGNING_ALLOWED = NO so the bundle is produced complete; the
release pipeline ad-hoc signs it afterward. Notarization is a later step.
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>
The old 'F∆I Platform' product name and platform@flemming.ai contact
survived in docs/NOTICE/descriptions/help text; the product is Ch∆In and
the contact is chain@flemming.ai. Generic 'cross-platform/platform-native'
left untouched.
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>