refactor: rename internal Fai* design system + fai_ helpers to chain
Some checks failed
Security / Security check (push) Failing after 2s

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>
This commit is contained in:
flemming-it 2026-06-16 17:53:17 +02:00
parent 68d23ab7dd
commit 891acd2ba2
52 changed files with 1225 additions and 1225 deletions

View file

@ -8,7 +8,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'data/fai_log.dart';
import 'data/chain_log.dart';
import 'data/hub.dart';
import 'data/system_actions.dart';
import 'data/theme_plugin.dart';
@ -22,7 +22,7 @@ import 'pages/store.dart';
import 'pages/welcome.dart';
import 'theme/theme.dart';
import 'theme/tokens.dart';
import 'widgets/fai_search_palette.dart';
import 'widgets/chain_search_palette.dart';
import 'widgets/widgets.dart';
/// Studio's own build version. Bump on every UI commit so the
@ -55,7 +55,7 @@ class StudioApp extends StatefulWidget {
/// Capability name of the active theme plugin (e.g.
/// `studio.theme.solarized`) or `null` for the built-in
/// FaiTheme.
/// ChainTheme.
final String? initialThemePlugin;
const StudioApp({
@ -89,7 +89,7 @@ class StudioAppState extends State<StudioApp> {
/// Capability name of the active `studio.theme.*` plugin
/// (e.g. `studio.theme.solarized`) or `null` for
/// FaiTheme's built-in palette. Flipping this triggers a
/// ChainTheme's built-in palette. Flipping this triggers a
/// re-fetch of the plugin's ColorSchemes; the MaterialApp
/// rebuilds with the new themes.
late final ValueNotifier<String?> themePluginNotifier;
@ -188,7 +188,7 @@ class StudioAppState extends State<StudioApp> {
// own "applied" snackbar is replaced upstream by the
// friendlier failure message via [themePluginFailed].
// ignore: discarded_futures
FaiLog.instance.error(
ChainLog.instance.error(
'theme.plugin.load',
e,
context: 'capability=$capability',
@ -217,8 +217,8 @@ class StudioAppState extends State<StudioApp> {
return MaterialApp(
title: 'Ch∆In Studio',
debugShowCheckedModeBanner: false,
theme: p.light ?? FaiTheme.light(),
darkTheme: p.dark ?? FaiTheme.dark(),
theme: p.light ?? ChainTheme.light(),
darkTheme: p.dark ?? ChainTheme.dark(),
themeMode: _flutterMode(mode),
locale: locale,
supportedLocales: AppLocalizations.supportedLocales,
@ -268,7 +268,7 @@ class StudioShellState extends State<StudioShell> {
/// row and the WelcomePage hero CTA.
Future<void> startDaemon() async {
final l = AppLocalizations.of(context)!;
final r = await SystemActions.faiDaemon(['start']);
final r = await SystemActions.chainDaemon(['start']);
if (!mounted) return;
final detail = r.stderr.trim().isEmpty ? r.stdout.trim() : r.stderr.trim();
ScaffoldMessenger.of(context).showSnackBar(
@ -325,7 +325,7 @@ class StudioShellState extends State<StudioShell> {
// (permissions, on-disk path, uninstall) now lives inside
// the Store's detail sheet, and the Store with the
// "Installed" filter covers the listing role. Cmd+K still
// opens FaiModuleSheet for quick info.
// opens ChainModuleSheet for quick info.
// Flows destination IS the editor as of 0.52.0 the
// graph / text / run tabs all live behind one icon. The
// separate "flow-editor" destination is gone; the Cmd+K
@ -413,9 +413,9 @@ class StudioShellState extends State<StudioShell> {
void _openSearchPalette() {
final l = AppLocalizations.of(context)!;
final pagesGroup = l.searchGroupPages;
final hits = <FaiSearchHit>[
final hits = <ChainSearchHit>[
for (var i = 0; i < _pages.length; i++)
FaiSearchHit(
ChainSearchHit(
label: _pages[i].labelOf(context),
hint: l.searchPageHint(i + 1),
icon: _pages[i].icon,
@ -425,18 +425,18 @@ class StudioShellState extends State<StudioShell> {
setState(() => _selectedIndex = i);
},
),
FaiSearchHit(
ChainSearchHit(
label: l.searchSettingsLabel,
hint: l.searchSettingsHint,
icon: Icons.settings_outlined,
group: pagesGroup,
onSelect: () {
Navigator.of(context).pop();
FaiSettingsDialog.show(context);
ChainSettingsDialog.show(context);
},
),
];
FaiSearchPalette.show(context, staticHits: hits);
ChainSearchPalette.show(context, staticHits: hits);
}
@override
@ -481,7 +481,7 @@ class StudioShellState extends State<StudioShell> {
),
_OpenSettingsIntent: CallbackAction<_OpenSettingsIntent>(
onInvoke: (_) {
FaiSettingsDialog.show(context);
ChainSettingsDialog.show(context);
return null;
},
),
@ -513,13 +513,13 @@ class StudioShellState extends State<StudioShell> {
if (_hubUnreachable)
_HubUnreachableBanner(
endpoint: HubService.instance.endpointLabel,
onOpenSettings: () => FaiSettingsDialog.show(context),
onOpenSettings: () => ChainSettingsDialog.show(context),
),
Expanded(
child: AnimatedSwitcher(
duration: FaiMotion.base,
switchInCurve: FaiMotion.easing,
switchOutCurve: FaiMotion.easing,
duration: ChainMotion.base,
switchInCurve: ChainMotion.easing,
switchOutCurve: ChainMotion.easing,
transitionBuilder: (child, anim) => FadeTransition(
opacity: anim,
child: SlideTransition(
@ -569,8 +569,8 @@ class _HubUnreachableBanner extends StatelessWidget {
color: theme.colorScheme.errorContainer,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: FaiSpace.lg,
vertical: FaiSpace.sm,
horizontal: ChainSpace.lg,
vertical: ChainSpace.sm,
),
child: Row(
children: [
@ -579,7 +579,7 @@ class _HubUnreachableBanner extends StatelessWidget {
size: 18,
color: theme.colorScheme.onErrorContainer,
),
const SizedBox(width: FaiSpace.sm),
const SizedBox(width: ChainSpace.sm),
Expanded(
child: Text(
l.hubUnreachableBanner(endpoint),
@ -588,7 +588,7 @@ class _HubUnreachableBanner extends StatelessWidget {
),
),
),
const SizedBox(width: FaiSpace.sm),
const SizedBox(width: ChainSpace.sm),
TextButton(
onPressed: onOpenSettings,
child: Text(l.hubUnreachableOpenSettings),
@ -674,8 +674,8 @@ class _SidebarState extends State<_Sidebar>
// reveal is a deliberate, eased gesture, not a flicker.
// The collapse runs faster (reverseDuration) so dismissing
// the rail feels crisp rather than sluggish.
duration: FaiMotion.slow,
reverseDuration: FaiMotion.base,
duration: ChainMotion.slow,
reverseDuration: ChainMotion.base,
value: 0,
);
}
@ -688,7 +688,7 @@ class _SidebarState extends State<_Sidebar>
Future<void> _startDaemon(BuildContext context) async {
final l = AppLocalizations.of(context)!;
final r = await SystemActions.faiDaemon(['start']);
final r = await SystemActions.chainDaemon(['start']);
if (!context.mounted) return;
final detail = r.stderr.trim().isEmpty ? r.stdout.trim() : r.stderr.trim();
ScaffoldMessenger.of(context).showSnackBar(
@ -704,8 +704,8 @@ class _SidebarState extends State<_Sidebar>
Widget build(BuildContext context) {
final theme = Theme.of(context);
final mode = widget.connected == true
? FaiDeltaMode.live
: FaiDeltaMode.idle;
? ChainDeltaMode.live
: ChainDeltaMode.idle;
final hasChannel =
widget.activeChannel != null && widget.activeChannel!.isNotEmpty;
return MouseRegion(
@ -721,7 +721,7 @@ class _SidebarState extends State<_Sidebar>
return Container(
width: width,
color: theme.colorScheme.surfaceContainerLow,
padding: const EdgeInsets.symmetric(vertical: FaiSpace.xl),
padding: const EdgeInsets.symmetric(vertical: ChainSpace.xl),
child: ClipRect(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -730,7 +730,7 @@ class _SidebarState extends State<_Sidebar>
SizedBox(
height: _brandRowH,
child: _sidebarRow(
leading: FaiDeltaMark(
leading: ChainDeltaMark(
color: theme.colorScheme.primary,
mode: mode,
),
@ -796,7 +796,7 @@ class _SidebarState extends State<_Sidebar>
)
: const SizedBox.shrink(),
),
const SizedBox(height: FaiSpace.md),
const SizedBox(height: ChainSpace.md),
Expanded(
child: ListView(
padding: EdgeInsets.zero,
@ -868,7 +868,7 @@ class _SidebarState extends State<_Sidebar>
child: Opacity(
opacity: t,
child: Padding(
padding: const EdgeInsets.only(right: FaiSpace.md),
padding: const EdgeInsets.only(right: ChainSpace.md),
child: label,
),
),
@ -889,7 +889,7 @@ class _SidebarState extends State<_Sidebar>
}
Future<void> _openSettings(BuildContext context) async {
final saved = await FaiSettingsDialog.show(context);
final saved = await ChainSettingsDialog.show(context);
if (saved && context.mounted) {
// Force a sidebar rebuild so the new endpoint shows in
// the connection pill.
@ -911,7 +911,7 @@ class _ChannelPill extends StatelessWidget {
case 'production':
return cs.error;
case 'beta':
return FaiColors.warning;
return ChainColors.warning;
case 'dev':
return cs.primary;
case 'local':
@ -943,17 +943,17 @@ class _ChannelPill extends StatelessWidget {
message: l.sidebarChannelTooltip,
child: Material(
color: theme.colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(FaiRadius.sm),
borderRadius: BorderRadius.circular(ChainRadius.sm),
child: InkWell(
borderRadius: BorderRadius.circular(FaiRadius.sm),
onTap: () => FaiSettingsDialog.show(context),
borderRadius: BorderRadius.circular(ChainRadius.sm),
onTap: () => ChainSettingsDialog.show(context),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: FaiSpace.sm,
horizontal: ChainSpace.sm,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(FaiRadius.sm),
borderRadius: BorderRadius.circular(ChainRadius.sm),
border: Border.all(color: accent.withValues(alpha: 0.4)),
),
child: Row(
@ -963,7 +963,7 @@ class _ChannelPill extends StatelessWidget {
const SizedBox(width: 4),
Text(
channel,
style: FaiTheme.mono(
style: ChainTheme.mono(
size: 10,
weight: FontWeight.w600,
color: accent,
@ -980,7 +980,7 @@ class _ChannelPill extends StatelessWidget {
/// Mini-version of [_ConnectionLabel] used when the sidebar is
/// collapsed. A 10px dot in the same green/red/amber tonality
/// the FaiDeltaMark uses for live / idle / unknown.
/// the ChainDeltaMark uses for live / idle / unknown.
class _CollapsedConnectionDot extends StatelessWidget {
final bool? connected;
const _CollapsedConnectionDot({required this.connected});
@ -989,10 +989,10 @@ class _CollapsedConnectionDot extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final color = connected == true
? FaiColors.success
? ChainColors.success
: connected == false
? theme.colorScheme.error
: FaiColors.warning;
: ChainColors.warning;
return Container(
width: 10,
height: 10,
@ -1025,7 +1025,7 @@ class _CollapsedChannelChip extends StatelessWidget {
case 'production':
return cs.error;
case 'beta':
return FaiColors.warning;
return ChainColors.warning;
case 'dev':
return cs.primary;
case 'local':
@ -1053,7 +1053,7 @@ class _CollapsedChannelChip extends StatelessWidget {
alignment: Alignment.center,
child: Text(
_letter,
style: FaiTheme.mono(size: 10, weight: FontWeight.w700, color: accent),
style: ChainTheme.mono(size: 10, weight: FontWeight.w700, color: accent),
),
);
}
@ -1080,7 +1080,7 @@ class _BrandLabel extends StatelessWidget {
const SizedBox(height: 2),
Text(
'v$kStudioVersion',
style: FaiTheme.mono(size: 10, color: theme.colorScheme.primary),
style: ChainTheme.mono(size: 10, color: theme.colorScheme.primary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@ -1133,7 +1133,7 @@ class _ConnectionLabel extends StatelessWidget {
endpoint,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: FaiTheme.mono(
style: ChainTheme.mono(
size: 10,
color: theme.colorScheme.onSurfaceVariant,
),
@ -1251,7 +1251,7 @@ class _SidebarItemState extends State<_SidebarItem> {
child: Opacity(
opacity: widget.t,
child: Padding(
padding: const EdgeInsets.only(right: FaiSpace.md),
padding: const EdgeInsets.only(right: ChainSpace.md),
child: Text(
label,
overflow: TextOverflow.fade,
@ -1278,19 +1278,19 @@ class _SidebarItemState extends State<_SidebarItem> {
behavior: HitTestBehavior.opaque,
onTap: widget.onTap,
child: AnimatedContainer(
duration: FaiMotion.fast,
duration: ChainMotion.fast,
// No horizontal padding the icon column anchors
// the left. The bg highlight spans the rail's
// current width (typical nav-rail behaviour).
padding: const EdgeInsets.symmetric(vertical: FaiSpace.md),
padding: const EdgeInsets.symmetric(vertical: ChainSpace.md),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(FaiRadius.sm),
borderRadius: BorderRadius.circular(ChainRadius.sm),
// Lift only the selected item a whisper of depth
// marks "you are here" without competing with the
// accent fill.
boxShadow: widget.selected
? FaiElevation.low(theme.brightness)
? ChainElevation.low(theme.brightness)
: null,
),
child: content,
@ -1348,7 +1348,7 @@ class _Footer extends StatelessWidget {
child: Opacity(
opacity: t,
child: Padding(
padding: const EdgeInsets.only(right: FaiSpace.sm),
padding: const EdgeInsets.only(right: ChainSpace.sm),
child: Row(
children: [
_ThemeToggle(),
@ -1515,7 +1515,7 @@ class _SidebarClockState extends State<_SidebarClock> {
message: tooltip,
child: Text(
'$hh:$mm:$ss',
style: FaiTheme.mono(
style: ChainTheme.mono(
size: 11,
color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.85),
),
@ -1553,7 +1553,7 @@ class _LanguageToggle extends StatelessWidget {
),
child: Text(
isDe ? 'DE' : 'EN',
style: FaiTheme.mono(
style: ChainTheme.mono(
size: 11,
weight: FontWeight.w600,
color: Theme.of(context).colorScheme.primary,