feat(studio): first-run UX, recovery affordances, l10n, bundled fonts

- 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>
This commit is contained in:
flemming-it 2026-06-11 23:52:18 +02:00
parent 7511867774
commit 5313266cc4
25 changed files with 1231 additions and 234 deletions

View file

@ -11,6 +11,7 @@ import 'package:fai_client_sdk/fai_client_sdk.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../l10n/app_localizations.dart';
import 'flow_output.dart';
import 'hub_auth_token.dart';
export 'flow_output.dart';
@ -1306,24 +1307,25 @@ class AskAiResult {
/// One-line fix hint per error kind, mirroring
/// `docs/architecture/system-ai.md`. Empty on success.
String get fixHint {
/// Localized pass the active [AppLocalizations].
String fixHint(AppLocalizations l) {
switch (errorKind) {
case '':
return '';
case 'disabled':
return 'Configure System AI in Settings (Cmd+,) → System AI panel.';
return l.sysAiFixDisabled;
case 'env_missing':
return 'The API-key env var is empty. `export <var>=<key>` in your shell, then `fai daemon restart`.';
return l.sysAiFixEnvMissing;
case 'network':
return 'Hub cannot reach the configured endpoint. Is your provider running?';
return l.sysAiFixNetwork;
case 'http':
return 'Provider returned a non-2xx status. Verify endpoint, model name, and API key.';
return l.sysAiFixHttp;
case 'parse':
return 'Provider returned an unexpected response shape. Non-OpenAI providers may need a compatibility proxy.';
return l.sysAiFixParse;
case 'empty_response':
return 'Provider answered with no content. Try a different model or rephrase the prompt.';
return l.sysAiFixEmptyResponse;
default:
return 'Unknown failure kind ($errorKind). See system-ai.md.';
return l.sysAiFixUnknown(errorKind);
}
}
}