Commit graph

15 commits

Author SHA1 Message Date
flemming-it
de22791e86 feat(studio): plain-language store, bottom-anchored ask bar (v0.33.0)
The store had three structural problems flagged in user
feedback:

1. "Lernkurve zu hoch — alle bridge, debug, alpha, planned,
   keiner weiß was das heißt." Wire-level enum values bled
   through into the UI: `bridge`, `debug`, `published`,
   `alpha`, `planned`. Operators don't share the data model.

2. "Filter / Kategorien sollten oben in die Leiste neben Store
   zum ausklappen, der Body soll übersichtlicher werden." A
   chip-row plus category strip plus result-count line ate a
   full row of viewport on every screen.

3. "Suche passt besser an den unteren Bildschirmrand." The
   chat-style ask bar belongs at the bottom — Claude / ChatGPT
   / Slack pattern — not at the top where it competes with
   the Today hero.

Plus: "Es gibt noch ganz viele overflows in den Beschreibungen."

Changes:

- Plain-language display names. New ARB keys for category
  labels (Connectors / Sample modules / AI models / Storage /
  Channels / Authentication / Orchestration / …) and updated
  status values (stable / experimental / coming soon). Wire
  ids stay in StoreEntry, RPCs, seed.yaml — only the rendered
  pills and dropdowns get translated. Helpers
  `_categoryDisplayName` and `_statusDisplayName` keep the
  mapping in one place.

- Toolbar moves into the AppBar. The new `_CategoryDropdown`
  hosts the category picker as a popup-menu with localised
  labels; the existing `_FilterButton` lives next to it; the
  reload icon stays where it always was. The body no longer
  carries any chip strip or result-count line.

- Bottom-anchored `_AskBar`. The Scaffold body becomes a
  Column of `Expanded(scrollable content)` plus a pinned
  composer row at the foot of the viewport, with a top
  divider matching the chat-input pattern of modern AI
  assistants. AI answers now render at the top of the scroll
  (above the Today-Hero) so the operator sees them right
  after submitting the question at the bottom.

- Overflow sweep on descriptions. Today-Hero header row
  becomes a Wrap (badge + deck flow naturally on narrow
  windows), the title is bound to 3 lines, the body to 6.
  Card category text gets `maxLines: 1, ellipsis` in both
  StoreCard and FeaturedTile. Recommended-source card title
  gets the same treatment.

- Better toast for the "added but zero capabilities" path.
  When MCP discovery succeeds but returns no tools (typical
  Streamable-HTTP servers without Mcp-Session-Id support, or
  servers that need `notifications/initialized`), the toast
  now explains the situation in plain language and points
  the operator at Settings → MCP Clients to retry. Old
  pluralised toast still fires when N > 0.

Hub-side `notifications/initialized` for HTTP MCP and
Mcp-Session-Id support are out of scope for this commit;
tracked as a separate fai_hub follow-up.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:37:35 +02:00
flemming-it
c7869870c4 feat(studio): plain-language ask bar + collapsible filter + AI search (v0.32.0)
Three changes against the user feedback "der text ist zu
zerhackt, die filter-leiste nimmt zu viel sicht weg, llm-suche
wenn das geht":

1. Today-Hero copy rewritten in flowing prose. The fallback
   story drops the code-fence templates ("`mcp.<server>.<tool>`")
   and reads as a single arc per language. Same trust model,
   gentler register.

2. Filter row collapses behind a single `_FilterButton` with a
   "Filter · N active" count badge. Status / Source / Installed
   chips now live inside `_FilterDialog` — invisible until the
   operator wants them, recovers a full row of viewport. The
   category strip stays inline because category is the most
   common cut and benefits from being one click away.

3. New `_AskBar` replaces the old single-line `_SearchField`:

   - Multi-line input (1-4 lines auto-grow) so questions don't
     overflow horizontally.
   - Cmd+Enter / Ctrl+Enter submits; bare Enter inserts a
     newline so the operator can write multi-line questions
     naturally.
   - Heuristic question detector (ends in `?` or ≥4 words)
     routes the submit to the System-AI's askAi RPC instead of
     the substring search. Live keystrokes still keyword-search
     for short queries; question-shaped input holds the grid
     steady until submit so the visible result set doesn't
     wipe with every space.
   - The LLM is asked for a strict-JSON ranking of up to 5
     modules with a one-phrase reason each. Unknown module
     names are dropped silently — operators must not see
     hallucinated entries.
   - The new `_AiAnswerCard` renders the LLM's answer plus the
     ranked match list above the grid; the grid filters to
     just those names so the answer and the visible cards
     stay coherent. Clearing the question collapses everything
     back.
   - Falls back to plain keyword search when System AI is off
     (with an explanatory hint instead of the AI hint).

The AI path uses the System-AI the operator already configured
in Settings; same privacy mode, same audit-log trail. Nothing
new leaves the hub.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:21:40 +02:00
flemming-it
b0f09260e1 fix(studio): store overflow + visual clutter (v0.31.1)
Two issues from the user feedback after v0.31.0:

1. RenderFlex overflow in the store body. The inner Column
   wrapped the editorial chrome (Today, Recommended,
   Featured) plus an Expanded grid; on small windows the
   chrome alone exceeded the available height and the grid
   got squeezed past zero, painting the yellow-and-black
   stripe.

   Fix: wrap the inner Column in a SingleChildScrollView so
   chrome and grid scroll as one continuous surface
   (App-Store / Play-Store behaviour). The grid switches to
   `shrinkWrap: true` + `NeverScrollableScrollPhysics()` so
   it doesn't try to claim its own viewport.

2. "Der Store ist zu unaufgeräumt, ich fühle mich
   erschlagen." — three editorial cards stacked above the
   filter row + grid was too much.

   Visual cleanup:
   - The recommended-source quick-add chips are now inlined
     into the Today hero's footer (same row as the CTA).
     The standalone `_RecommendedSourcesStrip` only fires in
     the corner case where Today is dismissed AND no
     federation exists yet.
   - The Featured strip no longer competes with Today —
     it only renders once Today has been dismissed. Today
     plays the editorial-hero role; Featured is the
     fallback editorial surface.
   - Provenance pill ("native") is dropped on native cards.
     Native is the default and doesn't earn a badge — only
     foreign code (mcp / n8n) gets the provenance pill, the
     same way "verified" is opt-in in commercial app stores.

Net: at most one editorial card above the grid at any time.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:06:54 +02:00
flemming-it
ce97300a12 feat(studio): daily Today-Hero proposal pipeline (v0.31.0)
Cross-store research (Apple, Play, Steam, Docker, VS Code,
Chrome Web Store, Flathub) consistently rewards editorial
curation over algorithmic recommendations — but manual
copywriting per release does not survive a solo-dev cadence.
This commit lands a daily-build pipeline so the Today-Hero
card stays fresh without operator hand-edits per release.

Pipeline shape (full design in docs/today-pipeline.md):

1. tools/today/collect.sh aggregates "what happened in the
   last 24 hours" across the F∆I monorepos: git log per repo,
   store-index seed.yaml diffs, architecture/system-gaps doc
   changes, Studio release tags, and (opt-in) audit-log
   highlights. Outputs plain text.

2. tools/today/propose.sh feeds the signal summary plus
   prompt.template.md to the operator's already-configured
   System-AI (Ollama default; OpenAI-compatible endpoints
   work via env-var override). Drafts N candidate stories as
   YAML files under ~/.fai/today/proposals/<date>/.

3. tools/today/accept.sh validates a chosen candidate against
   the today/v1 schema and the no-marketing-speak banned-word
   list, then atomic-renames it into ~/.fai/today/active.yaml.

4. Studio reads active.yaml at store-page init via the new
   TodayStoryLoader (lib/data/today_story_loader.dart). On any
   failure (file missing, schema mismatch, banned-words hit,
   parse error) it falls back to the compiled-in
   _kFallbackTodayStory so KRITIS deployments and fresh
   installs always render something sensible.

Trust + audit:
- All proposed and accepted stories live as plain YAML on disk.
- The pipeline calls only the operator's already-configured
  System-AI; it never reaches a CMS, never phones home, works
  air-gapped if the System-AI does.
- The bash accept gate AND the Dart loader both enforce the
  banned-word list — a hand-edited active.yaml that bypassed
  the shell still won't reach the UI.
- Removing the cron entry disables the pipeline; Studio falls
  back to the const story and continues to work.

Cron / launchd / systemd recipes documented in
tools/today/README.md.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 12:59:33 +02:00
flemming-it
fe933a713f feat(studio): editorial Today hero on the store (v0.30.0)
App-store research shows that the most loved discovery
surfaces — Apple's Today tab being the canonical example —
work because editors tell stories instead of stacking
algorithmic recommendations. F∆I has no surveillance budget
and no monetization pressure, so we lean fully into editorial
curation.

This commit adds `_StoreTodayHero`, the first surface a
browsing operator sees:

- Single curated story per release, kept const in
  [_kCurrentTodayStory] so the narrative is reviewable in code
  review and ships in the audit log via the binary hash. No
  CMS, no network, no surveillance.
- Bilingual content shipped inline (`titleEn`/`titleDe`,
  `bodyEn`/`bodyDe`) so KRITIS deployments don't need a
  translation backend.
- Gradient backdrop with hero icon, deck, narrative paragraph,
  optional CTA. Visual treatment matches Apple Today's
  hierarchy: badge → headline → body → action.
- Auto-hides whenever a filter is active so a purposeful
  search isn't pushed below the fold.
- Per-session dismiss button — no permanent suppression, the
  next Studio launch shows it again so a release-bumped story
  has a chance to be seen.

Current story (Studio v0.30.x) directs operators to the new
recommended-sources strip, closing the loop between editorial
context and one-click action.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 12:44:39 +02:00
flemming-it
581ebbeaf7 feat(studio): store-side source filter, provenance pills, one-click recommended sources (v0.29.0)
The Store is now the centre of capability discovery — provider
configuration moves out of Settings into the Store itself.
Three changes work together:

1. Source filter chips next to the existing status chips:
   All sources / Native / MCP / n8n. Applied client-side after
   the hub returns results so toggling is instant. The result
   count and the "Clear filters" reset both account for the
   source filter too.

2. Per-card provenance pill (`_ProvenancePill`): shows whether
   each entry is native, mcp · <provider>, or n8n · <provider>
   so the operator can triage the source at a glance — same
   role the "verified" badge plays in commercial app stores.

3. `_RecommendedSourcesStrip` replaces the older
   `_FederationNudge`. Renders curated public MCP servers
   (DeepWiki, Semgrep) as one-click cards with an inline
   `[+ Add]` button — no Settings detour, no form. Both servers
   are HTTPS Streamable-HTTP, no API key, no subprocess.
   Useful AI was considered but its 340+ tools would drown the
   index — kept out of the curated list. The strip auto-hides
   the moment any federated entry exists.

Removed the now-orphaned storeFederationNudge* ARB keys.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 12:25:59 +02:00
flemming-it
e2b2639a86 feat(studio): Store + Cmd+K palette i18n (v0.27.0)
- Localize Store page: search hint, category and status filter
  chips (All / Published / Alpha / Planned / Installed),
  pluralized result count, hub-unreachable / no-matches empty
  states, featured strip header, store-card pills (installed /
  update / version), Install / Update / Details / Read docs /
  Uninstall / Not installable buttons, install-progress dialog,
  uninstall confirm dialog, install / uninstall toasts,
  open-browser failure toast.
- Localize detail-sheet sections: Tags, Required capabilities,
  Required host services, Screenshots, Documentation, Source.
- Localize docs panel: Load documentation button, fetching
  spinner copy, Open repository in browser button, friendly
  error mapping (not_found / no_docs / auth / network / parse).
- Localize Cmd+K palette: search hint, group labels (Pages /
  Modules / Store / Flows), keyboard hint footer, indexing /
  no-matches states, dynamic-hit copy ("installed module ·
  v{version}", "saved flow", "uncategorized"). Static page
  hits now flow through the localized "Pages" group; Settings
  entry uses the localized label and hint.

Status pill values ("published", "alpha", "planned") stay as
data-derived English strings since they map directly to the
store-index `status:` enum.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 02:49:18 +02:00
flemming-it
349619d68e feat(studio): Doctor + Modules localized + sparse-store federation nudge (v0.25.0)
Two threads.

Translation expansion: every visible string on the Doctor
page (section headers, status text, button labels, daemon-
control card, daemon-files panel, update banner) and the
Modules page (recent-activity strip, capabilities label,
uninstall dialog + toast) flips between DE and EN with the
sidebar toggle. Adds ~50 ARB keys split between
`app_en.arb` / `app_de.arb`. Pluralised + parametrised
strings (`{n} events verified`, `Running on {name}: {endpoint}`)
use the standard ICU placeholder syntax so future locales
slot in without code changes.

Sparse-store federation nudge: the Store page renders an
inline banner above the grid when the operator has zero
federated entries — single biggest store-fullness lever is
configuring an MCP server / n8n endpoint, so the banner
says exactly that and the button opens Settings straight
to the editor. Banner dismisses automatically the next
render after a federated entry appears.

Coverage stand for translation: Doctor + Modules + sidebar
+ page titles + nav + Cmd+K labels are bilingual. Settings
dialog, Approvals cards, Audit drilldown, MCP/n8n editors,
Store search hint + filter chips remain English-literal.
The infrastructure (ARB plumbing, generator hookup,
locale-notifier) means each follow-up surface is a
one-line ARB edit + one call-site swap.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 01:39:42 +02:00
flemming-it
ee83eb851a feat(studio): app-wide i18n via flutter_localizations (v0.24.0)
Replaces the Store-only DE/EN toggle with an app-wide one
parked in the sidebar footer next to the theme button.
Pressing it flips every translated string at once: nav
labels, page titles, common buttons, the bilingual
store-index content.

Implementation:
- Adds `flutter_localizations` + `intl` to pubspec, plus
  `flutter.generate: true` so `flutter gen-l10n` runs in the
  build pipeline.
- ARB sources at `lib/l10n/app_en.arb` and `app_de.arb`. The
  EN file is the template; DE carries the German strings.
  Initial coverage: navigation, common buttons, page titles,
  channels / store / audit / modules / approvals headers,
  hub-unreachable copy, MCP + n8n panel headers + hints.
  Rest of the UI strings are still English-literal — those
  fall in incrementally as we touch each surface.
- Generated `AppLocalizations` lives at
  `lib/l10n/app_localizations*.dart` (regenerated via
  `flutter gen-l10n` on every ARB edit).
- `StudioAppState` gains `localeNotifier` alongside
  `modeNotifier`; persisted via SharedPreferences key
  `locale.code`.
- Sidebar `_LanguageToggle` reads/writes through the
  notifier. The Store's per-page locale state is gone:
  `_locale` now reads `Localizations.localeOf(context)
  .languageCode`, so the bilingual store-index content
  follows the global setting without a second toggle.
- `_NavPage.label` becomes `_NavPage.id` + `labelOf(context)`;
  Cmd+K palette and Sidebar both read the localized label.

Out of scope this iteration: localizing the remaining
~80% of UI strings (Settings dialog labels, Store search
hint, error messages). Those land incrementally — the i18n
infrastructure now means each is a one-line ARB edit + one
call-site swap.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 01:19:32 +02:00
flemming-it
11b0ac97a1 feat(studio): Cmd+K palette, recent-activity panel, icon/screenshot rendering (v0.21.0)
Three sweeps in a single bundle.

Universal command palette (⌘K / ctrl+K):
- Modal at top-of-window with a single search input. Indexes
  pages, installed modules, store entries, saved flows on
  open; filters client-side as the operator types.
- Keyboard nav (↑/↓ + Enter), grouped sections, hover-to-
  highlight. Hit selection navigates / opens the right
  surface in one keystroke. Closes with Esc.
- Designed to mirror the VSCode / Linear / 1Password
  ergonomics — gives non-CLI operators a "jump anywhere"
  affordance that scales with the number of installed
  modules.

Modules page recent-activity panel:
- Top-of-page strip lists the last 10 install / uninstall
  events from the audit log, color-coded by direction.
  Hidden when no relevant events exist (fresh installs).
  Same locale-unambiguous timestamp format used in audit.

Store detail sheet now renders icons + screenshots:
- `_ModuleIcon` widget loads the explicit `iconUrl` if
  provided, falls back to the category glyph on missing
  URL or load failure (no broken-image rectangle).
- Screenshots strip below the description: 320×200 tiles,
  horizontally-scrollable, click opens full-size via the
  OS handler. Placeholder card on load failure.

StoreItem extended with `iconUrl`, `screenshotUrls`,
`docsUrl` so the new content paths through unchanged.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 21:51:47 +02:00
flemming-it
fb7352d182 fix(studio): live-search exception, daemon-card width, featured tile size; add Start-hub button (v0.20.1)
Three reported bugs and one onramp gap:

- Store live-search threw `setState() callback returned a
  Future`. The `=>` body of `_runSearch` evaluated to the
  Future returned by `_load()`. Switched to a block body so
  the closure resolves to void; the future itself is still
  awaited by the FutureBuilder.

- Doctor's Daemon-control card was visibly narrower than its
  siblings — its only stretching child was a Wrap of small
  buttons. Wrapped the content in `SizedBox(width: infinity)`
  so the card fills the section's width like every other
  panel. Card now leads with the live `running on local:
  127.0.0.1:50051` status row + status pill so operators see
  state at a glance, then offers Restart / Start (when
  stopped) / Stop / Status.

- Featured tiles were 320×152 against the regular grid's
  ~360×168, so the editorial picks looked subordinate to
  the dense grid. Bumped to 480×220 with bigger icon, larger
  title, larger tagline so the strip reads as a hero band.

- ConnectionPill in the sidebar now offers an inline "Start
  hub" button when the daemon is unreachable. Spawns
  `fai daemon start` via SystemActions; the shell-level
  health poll picks the daemon up on its next tick. Closes
  the chicken-and-egg for Windows users who can't open a
  shell to bootstrap.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 21:27:09 +02:00
flemming-it
26691b7471 feat(studio): channel pill in sidebar + Featured strip in Store (v0.20.0)
Sidebar:
- New active-channel pill below the connection pill,
  color-coded so production deployments look visibly
  different from local-dev. Click opens Settings; tooltip
  explains the channel taxonomy. Polled in lockstep with the
  health probe so it tracks CLI-driven `fai channel switch`.

Store:
- Featured strip above the main grid renders editorial
  picks as bigger hero tiles with a subtle gradient
  backdrop, version + status pills, and a one-click
  Install. Hidden the moment the operator types in the
  search box or picks any filter — the result list is the
  answer they want, not editorial chrome.

StoreItem now carries the `featured` flag so the page can
filter without an extra round-trip.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 21:05:15 +02:00
flemming-it
04cc12bc54 feat(studio): inline README + per-module update badge in Store (v0.19.0)
Two Phase-2 Store improvements that operators feel
immediately:

- Per-module update badge: store cards compare the operator's
  installed version against the index's `best_version`, raise
  an "update" pill + "Update to vX.Y.Z" button when newer is
  available. Result: a single glance at the Store reveals
  what's behind. The page now fetches `listModules` in
  parallel with the search so the comparison is on the
  current snapshot.

- Inline README rendering: detail sheet has a new
  Documentation section. "Load documentation" button (lazy —
  no network until clicked) calls FetchModuleDocs and renders
  the markdown via flutter_markdown, with the operator's
  theme colors and link-tap routed through SystemActions.
  Auth / not-found / network failures fall back to a
  friendly fix-hint panel + "Open repository in browser"
  button so the operator never hits a dead end.

Adds flutter_markdown ^0.7.7 to pubspec; the package is
maintenance-only upstream but is the only mature option
for Material-themed markdown right now. Easy to swap to
markdown_widget if/when we need GitHub-flavored extras.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 20:46:16 +02:00
flemming-it
93926741b1 feat(studio): channel switcher, autostart toggle, Store redesign (v0.18.0)
UI parity for operators who never touch a CLI, plus a Store
that reads more like an app store.

Settings dialog:
- Channel rows gain a popup menu: Connect / Make active /
  Enable autostart / Disable autostart. "Connect" still
  re-points Studio's wire; "Make active" actually writes
  ~/.fai/current-channel via `fai channel switch`.
- Inline output panel surfaces the spawned binary's stdout
  on success or stderr on failure, so operators see what
  happened without opening a terminal.

Store page rewrite:
- Big top search bar with a clear button. Live filter on
  every keystroke.
- Horizontal category strip auto-populated from the index;
  segmented status row (All / Published / Alpha / Planned),
  Installed-only chip, result count.
- Grid of cards that reflows to fit the viewport — replaces
  the previous single-column list. Each card shows
  category-aware icon, version, status, tagline preview, and
  a one-click Install (or Details for installed / planned).
- Per-module detail sheet renders the full bilingual
  description with a DE/EN toggle, separate Required-
  capabilities + Required-host-services sections, repo link,
  Read-docs button. Install + Uninstall live at the bottom.
- StoreItem and HubService.searchStore now carry the German
  tagline + description so the locale toggle has something
  to switch to.

SystemActions extended with `faiChannelSwitch`,
`faiDaemonEnable`, `faiDaemonDisable` so Settings can spawn
the right CLI without each call site reimplementing the
`fai` resolution rules.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 18:52:48 +02:00
flemming-it
060c8003d5 feat(studio): operator-mode pass — Store + audit detail + channel switcher (v0.10.0)
Turns Studio from read-only dashboard into operator console.
Pieces:

  * **New Store page** (sidebar destination #3): browses the
    hub's bundled store-index with query + category + status
    filters. Each card has an Install button that prompts for
    the `.fai` bundle source (URL or local path), ships it to
    HubAdmin.InstallModule, shows success / error in a progress
    dialog, refreshes the list.

  * **Audit drill-down**: every event row is now tappable;
    opens a modal with all LoggedEvent fields including the
    new `detail` JSON pretty-printed in a code block. KRITIS
    forensic story: every audit row → full structured detail
    in two clicks.

  * **Approvals payload preview**: shipped already; now
    pretty-prints JSON when the preview parses as such, plus
    a clearer `PAYLOAD PREVIEW` label. Reviewer identity
    defaults to `$USER@studio` instead of the hard-coded
    `studio-mvp` so the audit trail records who acted.

  * **Channel switcher in Settings dialog**: the dialog now
    pulls HubAdmin.ChannelStatus and renders one row per
    channel (local / dev / beta / production) with port,
    running indicator, active marker. A "Connect" button
    on a running channel sets Studio's endpoint to that
    channel's port and reconnects in one click.

Cmd+1..6 keyboard shortcuts updated for the six destinations.
Widget test asserts every destination renders.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-07 11:54:31 +02:00