Some checks failed
Security / Security check (push) Failing after 1s
Store cards + detail-sheet now prefix the version pill with `~` and attach a tooltip for federated entries (MCP / n8n / Temporal). Upstream services don't honour semver, so the version pill is a label, not a contract — the tilde says "this number may change without a version bump." Three render sites updated to stay visually consistent: - compact card pill in grid view - expanded card pill row - detail-sheet header pill cluster EN + DE l10n entries added (`storeAdvisoryVersionTooltip`) and `app_localizations.dart` regenerated. dart analyze clean; flutter test green (11 tests). Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2148 lines
52 KiB
Dart
2148 lines
52 KiB
Dart
// ignore: unused_import
|
||
import 'package:intl/intl.dart' as intl;
|
||
import 'app_localizations.dart';
|
||
|
||
// ignore_for_file: type=lint
|
||
|
||
/// The translations for English (`en`).
|
||
class AppLocalizationsEn extends AppLocalizations {
|
||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||
|
||
@override
|
||
String get appTitle => 'F∆I Studio';
|
||
|
||
@override
|
||
String get navWelcome => 'Welcome';
|
||
|
||
@override
|
||
String get welcomeHeroTitle => 'F∆I Platform';
|
||
|
||
@override
|
||
String get welcomeHeroSubtitle =>
|
||
'Deterministic workflow engine for AI-assisted document processing in regulated environments.';
|
||
|
||
@override
|
||
String get welcomePillarHubTitle => 'Hub';
|
||
|
||
@override
|
||
String get welcomePillarHubBody =>
|
||
'One Rust binary that loads modules and runs flows. SQLite for state. No Docker, no message broker, no background services to babysit.';
|
||
|
||
@override
|
||
String get welcomePillarModuleTitle => 'Module';
|
||
|
||
@override
|
||
String get welcomePillarModuleBody =>
|
||
'A small WebAssembly component that does one thing. Declares the network endpoints, files, and environment variables it touches; the hub enforces the list.';
|
||
|
||
@override
|
||
String get welcomePillarFlowTitle => 'Flow';
|
||
|
||
@override
|
||
String get welcomePillarFlowBody =>
|
||
'A YAML file that chains modules together. Inputs go in, modules run in declared order, outputs come out — every step recorded in a hash-chained audit log.';
|
||
|
||
@override
|
||
String get welcomeTrustHeader => 'TRUST POSTURE';
|
||
|
||
@override
|
||
String get welcomeTrustSandboxTitle => 'Sandbox by default';
|
||
|
||
@override
|
||
String get welcomeTrustSandboxBody =>
|
||
'Every module ships with an explicit permission list — network endpoints, files, environment variables. The hub enforces it; nothing reaches outside the sandbox without operator approval.';
|
||
|
||
@override
|
||
String get welcomeTrustAuditTitle => 'Tamper-evident audit log';
|
||
|
||
@override
|
||
String get welcomeTrustAuditBody =>
|
||
'Flow runs, install / uninstall actions, approval decisions — all of them write into a hash-chained audit log. The Doctor page verifies the chain end-to-end on every load.';
|
||
|
||
@override
|
||
String get welcomeTrustAirgapTitle => 'Air-gap ready';
|
||
|
||
@override
|
||
String get welcomeTrustAirgapBody =>
|
||
'The whole hub fits in a single binary that runs on Linux, macOS and Windows. Once a module is installed, the flow it powers runs without further network access — perfect for regulated environments.';
|
||
|
||
@override
|
||
String get welcomeDocsHeader => 'DOCUMENTATION';
|
||
|
||
@override
|
||
String get welcomeDocsBody =>
|
||
'Operator-facing explainers, rendered inline. No browser, no external link — air-gap-friendly.';
|
||
|
||
@override
|
||
String get welcomeDocArchitectureTitle => 'Architecture in one paragraph';
|
||
|
||
@override
|
||
String get welcomeDocArchitectureBlurb =>
|
||
'Hub, Module, Flow — and how the three fit together.';
|
||
|
||
@override
|
||
String get welcomeDocSecurityTitle => 'Sandbox model';
|
||
|
||
@override
|
||
String get welcomeDocSecurityBlurb =>
|
||
'What a module declares, what the operator caps, what the hub enforces.';
|
||
|
||
@override
|
||
String get welcomeDocAuditTitle => 'Tamper-evident audit log';
|
||
|
||
@override
|
||
String get welcomeDocAuditBlurb =>
|
||
'How the hash chain works and why WORM-1 is enough for KRITIS.';
|
||
|
||
@override
|
||
String get welcomeDocFlowsTitle => 'Flow composition';
|
||
|
||
@override
|
||
String get welcomeDocFlowsBlurb =>
|
||
'YAML basics, templating reference, the extract→summarize example.';
|
||
|
||
@override
|
||
String get welcomeDocClose => 'Close';
|
||
|
||
@override
|
||
String welcomeDocFailedToLoad(String error) {
|
||
return 'Could not load documentation: $error';
|
||
}
|
||
|
||
@override
|
||
String get welcomeChecklistHeader => 'GETTING STARTED';
|
||
|
||
@override
|
||
String get welcomeChecklistBody =>
|
||
'Four steps to a working hub. Live state — refresh after changing anything.';
|
||
|
||
@override
|
||
String get welcomeChecklistAi => 'Configure System AI';
|
||
|
||
@override
|
||
String get welcomeChecklistAiHint =>
|
||
'Settings → System AI. Required for the AI search and inline failure explanations.';
|
||
|
||
@override
|
||
String get welcomeChecklistMcp => 'Add a public capability source';
|
||
|
||
@override
|
||
String get welcomeChecklistMcpHint =>
|
||
'Store → Today hero, or Settings → MCP Clients. DeepWiki and Semgrep are one click each.';
|
||
|
||
@override
|
||
String get welcomeChecklistModule => 'Install a text module';
|
||
|
||
@override
|
||
String get welcomeChecklistModuleHint =>
|
||
'Store → search \"text\" → Install. Try text.extract for PDFs and DOCX.';
|
||
|
||
@override
|
||
String get welcomeChecklistFlow => 'Run a saved flow';
|
||
|
||
@override
|
||
String get welcomeChecklistFlowHint =>
|
||
'Flows → pick one → Run. The bundled extract-summarize.yaml is a good first run.';
|
||
|
||
@override
|
||
String get welcomeChecklistAllDone => 'All four steps complete.';
|
||
|
||
@override
|
||
String get welcomeChecklistDismiss => 'Hide checklist';
|
||
|
||
@override
|
||
String get welcomeChecklistRefresh => 'Refresh';
|
||
|
||
@override
|
||
String get welcomeChecklistRefreshing => 'Checking…';
|
||
|
||
@override
|
||
String get welcomeChecklistDone => 'Done';
|
||
|
||
@override
|
||
String get welcomeChecklistTodo => 'Pending';
|
||
|
||
@override
|
||
String get navDoctor => 'Doctor';
|
||
|
||
@override
|
||
String get navModules => 'Modules';
|
||
|
||
@override
|
||
String get navStore => 'Store';
|
||
|
||
@override
|
||
String get navFlows => 'Flows';
|
||
|
||
@override
|
||
String get navAudit => 'Audit';
|
||
|
||
@override
|
||
String get navApprovals => 'Approvals';
|
||
|
||
@override
|
||
String get connectionConnected => 'connected';
|
||
|
||
@override
|
||
String get connectionUnreachable => 'unreachable';
|
||
|
||
@override
|
||
String get connectionConnecting => 'connecting…';
|
||
|
||
@override
|
||
String get connectionStartHub => 'Start hub';
|
||
|
||
@override
|
||
String get buttonCancel => 'Cancel';
|
||
|
||
@override
|
||
String get buttonSave => 'Save';
|
||
|
||
@override
|
||
String get buttonClose => 'Close';
|
||
|
||
@override
|
||
String get buttonRetry => 'Retry';
|
||
|
||
@override
|
||
String get buttonRefresh => 'Refresh';
|
||
|
||
@override
|
||
String get buttonInstall => 'Install';
|
||
|
||
@override
|
||
String get buttonUninstall => 'Uninstall';
|
||
|
||
@override
|
||
String get buttonDetails => 'Details';
|
||
|
||
@override
|
||
String get buttonAdd => 'Add';
|
||
|
||
@override
|
||
String get buttonRemove => 'Remove';
|
||
|
||
@override
|
||
String get buttonOpen => 'Open';
|
||
|
||
@override
|
||
String get buttonExplain => 'Explain';
|
||
|
||
@override
|
||
String get buttonReadDocs => 'Read docs';
|
||
|
||
@override
|
||
String get buttonCopy => 'Copy to clipboard';
|
||
|
||
@override
|
||
String get buttonCopied => 'Copied';
|
||
|
||
@override
|
||
String get buttonShowDetails => 'Show details';
|
||
|
||
@override
|
||
String get buttonHideDetails => 'Hide details';
|
||
|
||
@override
|
||
String get storeInstallableOnly => 'Installable only';
|
||
|
||
@override
|
||
String get storePillComingSoon => 'Coming soon';
|
||
|
||
@override
|
||
String storeNotInstallableInline(String status) {
|
||
return 'This module is on the roadmap (status: $status). It has no installable bundle yet — follow the repository for updates.';
|
||
}
|
||
|
||
@override
|
||
String get mcpSuggestionDeepwikiDesc =>
|
||
'Public HTTPS — GitHub repo documentation search (AI-powered). No Node, no API key.';
|
||
|
||
@override
|
||
String get mcpSuggestionSemgrepDesc =>
|
||
'Public HTTPS — security scanning for code vulnerabilities. No Node, no API key.';
|
||
|
||
@override
|
||
String get mcpSuggestionFilesystemDesc =>
|
||
'Anthropic — read / write files in /tmp. Edit the path before saving.';
|
||
|
||
@override
|
||
String get mcpSuggestionFetchDesc =>
|
||
'Anthropic — fetch arbitrary HTTP(S) URLs as markdown.';
|
||
|
||
@override
|
||
String get mcpSuggestionGithubDesc =>
|
||
'Anthropic — issues, PRs, repo files. Needs a GitHub PAT in the env var.';
|
||
|
||
@override
|
||
String get mcpSuggestionPuppeteerDesc =>
|
||
'Anthropic — headless browser automation for screenshots / scraping.';
|
||
|
||
@override
|
||
String get mcpSuggestionPostgresDesc =>
|
||
'Anthropic — read-only SQL queries against a Postgres database. Edit the URL.';
|
||
|
||
@override
|
||
String get mcpSuggestionSqliteDesc =>
|
||
'Anthropic — query a local SQLite file. Edit the path.';
|
||
|
||
@override
|
||
String get mcpSuggestionBraveSearchDesc =>
|
||
'Anthropic — web search via Brave. API key required.';
|
||
|
||
@override
|
||
String get mcpSuggestionMemoryDesc =>
|
||
'Anthropic — persistent knowledge graph for an agent\'s memory.';
|
||
|
||
@override
|
||
String get mcpSuggestionTimeDesc =>
|
||
'Anthropic — current time + timezone conversion.';
|
||
|
||
@override
|
||
String get mcpServerEnLanguageBadge =>
|
||
'Server text in English — Studio shows it as supplied.';
|
||
|
||
@override
|
||
String get themePluginHeader => 'Theme plugin';
|
||
|
||
@override
|
||
String get themePluginNone => 'Built-in (no plugin)';
|
||
|
||
@override
|
||
String get themePluginHint =>
|
||
'Pick an installed studio.theme.* plugin to re-skin the whole app. Install one from the Store first.';
|
||
|
||
@override
|
||
String get themePluginEmpty =>
|
||
'No theme plugins installed. Open the Store and pick one in the studio-plugin category.';
|
||
|
||
@override
|
||
String get settingsTitle => 'Hub endpoint';
|
||
|
||
@override
|
||
String get settingsHost => 'Host';
|
||
|
||
@override
|
||
String get settingsPort => 'Port';
|
||
|
||
@override
|
||
String get settingsTls => 'TLS';
|
||
|
||
@override
|
||
String get settingsSaveAndConnect => 'Save & connect';
|
||
|
||
@override
|
||
String get settingsLanguage => 'Language';
|
||
|
||
@override
|
||
String get settingsLanguageHint =>
|
||
'App language. Affects every page; bilingual store entries also flip via this toggle.';
|
||
|
||
@override
|
||
String get settingsHubEndpointHint =>
|
||
'Where should Studio connect? Default is the local hub at 127.0.0.1:50051.';
|
||
|
||
@override
|
||
String get settingsTlsSubtitle => 'https/grpc-secure';
|
||
|
||
@override
|
||
String get settingsPortError => 'port must be 1–65535';
|
||
|
||
@override
|
||
String get channelsBlurb =>
|
||
'Switch hub channel (writes ~/.fai/current-channel and restarts the daemon). Connect just changes Studio\'s wire.';
|
||
|
||
@override
|
||
String get channelsActionsTooltip => 'Channel actions';
|
||
|
||
@override
|
||
String get systemAiHeader => 'SYSTEM AI';
|
||
|
||
@override
|
||
String get systemAiEnabled => 'enabled';
|
||
|
||
@override
|
||
String get systemAiOff => 'off';
|
||
|
||
@override
|
||
String get systemAiEdit => 'Edit…';
|
||
|
||
@override
|
||
String get systemAiConfigure => 'Configure…';
|
||
|
||
@override
|
||
String get systemAiOffBlurb =>
|
||
'Off — failure explanations on the audit page are disabled. Click Configure… to pick a provider (Ollama / OpenAI / LM Studio / vLLM / Custom). Operator config is rewritten in place; no daemon restart needed.';
|
||
|
||
@override
|
||
String mcpServersCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'servers',
|
||
one: 'server',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String get mcpRediscoverTooltip => 'Re-run discovery';
|
||
|
||
@override
|
||
String get mcpAddTooltip => 'Add MCP server';
|
||
|
||
@override
|
||
String get mcpRemoveTooltip => 'Remove server';
|
||
|
||
@override
|
||
String mcpToolsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'tools',
|
||
one: 'tool',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String n8nEndpointsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'endpoints',
|
||
one: 'endpoint',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String n8nWorkflowsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'workflows',
|
||
one: 'workflow',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String get n8nRediscoverTooltip => 'Re-run discovery';
|
||
|
||
@override
|
||
String get n8nAddTooltip => 'Add n8n endpoint';
|
||
|
||
@override
|
||
String get n8nRemoveTooltip => 'Remove endpoint';
|
||
|
||
@override
|
||
String get addMcpTitle => 'Add MCP server';
|
||
|
||
@override
|
||
String get addMcpIntro =>
|
||
'Tools the server advertises via `tools/list` appear in the Store as `mcp.<name>.<tool>` capabilities.';
|
||
|
||
@override
|
||
String get addMcpSuggestionsLabel => 'Suggested servers — click to pre-fill';
|
||
|
||
@override
|
||
String get addMcpNameLabel => 'Name (no dots)';
|
||
|
||
@override
|
||
String get addMcpNameHint => 'filesystem';
|
||
|
||
@override
|
||
String get addMcpEndpointLabel => 'Endpoint';
|
||
|
||
@override
|
||
String get addMcpEndpointHint => 'http://127.0.0.1:3001/mcp';
|
||
|
||
@override
|
||
String get addMcpApiKeyLabel => 'API key env var (optional)';
|
||
|
||
@override
|
||
String get addMcpApiKeyHint => 'MCP_FILESYSTEM_TOKEN';
|
||
|
||
@override
|
||
String get addMcpNotesLabel => 'Notes (optional)';
|
||
|
||
@override
|
||
String get addMcpAddButton => 'Add + discover';
|
||
|
||
@override
|
||
String get addN8nTitle => 'Add n8n endpoint';
|
||
|
||
@override
|
||
String get addN8nIntro =>
|
||
'Active workflows surface in the Store as `n8n.<name>.<workflow_slug>` capabilities.';
|
||
|
||
@override
|
||
String get addN8nNameLabel => 'Name (no dots)';
|
||
|
||
@override
|
||
String get addN8nNameHint => 'ops';
|
||
|
||
@override
|
||
String get addN8nBaseUrlLabel => 'Base URL (without /api/v1)';
|
||
|
||
@override
|
||
String get addN8nBaseUrlHint => 'https://n8n.example.com';
|
||
|
||
@override
|
||
String get addN8nApiKeyLabel => 'API key env var (optional)';
|
||
|
||
@override
|
||
String get addN8nApiKeyHint => 'N8N_OPS_KEY';
|
||
|
||
@override
|
||
String get addN8nNotesLabel => 'Notes (optional)';
|
||
|
||
@override
|
||
String get addN8nAddButton => 'Add + discover';
|
||
|
||
@override
|
||
String addedMcpToast(String name) {
|
||
return 'Added MCP server \"$name\".';
|
||
}
|
||
|
||
@override
|
||
String addedN8nToast(String name) {
|
||
return 'Added n8n endpoint \"$name\".';
|
||
}
|
||
|
||
@override
|
||
String addFailedToast(String error) {
|
||
return 'Add failed: $error';
|
||
}
|
||
|
||
@override
|
||
String removeFailedToast(String error) {
|
||
return 'Remove failed: $error';
|
||
}
|
||
|
||
@override
|
||
String refreshFailedToast(String error) {
|
||
return 'Refresh failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get channelsHeader => 'CHANNELS';
|
||
|
||
@override
|
||
String get channelsActive => 'active';
|
||
|
||
@override
|
||
String get channelsRunning => 'running';
|
||
|
||
@override
|
||
String get channelsStopped => 'stopped';
|
||
|
||
@override
|
||
String get channelsConnect => 'Connect Studio to this channel';
|
||
|
||
@override
|
||
String get channelsSwitch => 'Make this the active channel';
|
||
|
||
@override
|
||
String get channelsEnableAutostart => 'Enable autostart at login';
|
||
|
||
@override
|
||
String get channelsDisableAutostart => 'Disable autostart';
|
||
|
||
@override
|
||
String get storeSearchHint =>
|
||
'Search modules — name, tagline, tag, capability…';
|
||
|
||
@override
|
||
String get storeAskHint =>
|
||
'What do you need? Try \"a module that reads tabular data\" or just type a keyword.';
|
||
|
||
@override
|
||
String get storeAskSubmit => 'Search';
|
||
|
||
@override
|
||
String get storeAskAi => 'Ask the AI';
|
||
|
||
@override
|
||
String get storeAskClear => 'Clear question';
|
||
|
||
@override
|
||
String get storeAskAiThinking => 'Looking through modules…';
|
||
|
||
@override
|
||
String get storeAskAiUnavailable =>
|
||
'Configure a System AI in Settings to ask questions in plain language.';
|
||
|
||
@override
|
||
String get storeAskNoMatches =>
|
||
'No matches yet — refine the question or browse the grid below.';
|
||
|
||
@override
|
||
String get storeAskAnswerLabel => 'AI suggestion';
|
||
|
||
@override
|
||
String get storeAskAnswerWhy => 'Why this matches';
|
||
|
||
@override
|
||
String get storeAskMatchPill => 'match';
|
||
|
||
@override
|
||
String get storeFilterLabel => 'Filter';
|
||
|
||
@override
|
||
String storeFilterActiveCount(int n) {
|
||
return '$n active';
|
||
}
|
||
|
||
@override
|
||
String get storeFilterReset => 'Reset filters';
|
||
|
||
@override
|
||
String get storeFilterApply => 'Done';
|
||
|
||
@override
|
||
String get storeFilterStatusGroup => 'Status';
|
||
|
||
@override
|
||
String get storeFilterSourceGroup => 'Source';
|
||
|
||
@override
|
||
String get storeFilterInstalledGroup => 'Show only installed';
|
||
|
||
@override
|
||
String get storeFeatured => 'FEATURED';
|
||
|
||
@override
|
||
String get storeFeaturedHint => 'curated picks · click for details';
|
||
|
||
@override
|
||
String get storeNoMatches => 'No matches';
|
||
|
||
@override
|
||
String get storeNoMatchesHint =>
|
||
'Adjust the filters or clear the search to see all entries.';
|
||
|
||
@override
|
||
String get storeClearFilters => 'Clear filters';
|
||
|
||
@override
|
||
String get storeStatusAll => 'All';
|
||
|
||
@override
|
||
String get storeStatusPublished => 'stable';
|
||
|
||
@override
|
||
String get storeStatusAlpha => 'experimental';
|
||
|
||
@override
|
||
String get storeStatusPlanned => 'coming soon';
|
||
|
||
@override
|
||
String get storeInstalledOnly => 'Installed';
|
||
|
||
@override
|
||
String get storeCategoryLabel => 'Category';
|
||
|
||
@override
|
||
String get storeCategoryAll => 'All categories';
|
||
|
||
@override
|
||
String get storeCategoryBridge => 'Connectors';
|
||
|
||
@override
|
||
String get storeCategoryDebug => 'Sample modules';
|
||
|
||
@override
|
||
String get storeCategoryText => 'Text';
|
||
|
||
@override
|
||
String get storeCategoryLlm => 'AI models';
|
||
|
||
@override
|
||
String get storeCategorySystem => 'System';
|
||
|
||
@override
|
||
String get storeCategoryAuth => 'Authentication';
|
||
|
||
@override
|
||
String get storeCategoryStorage => 'Storage';
|
||
|
||
@override
|
||
String get storeCategoryChannel => 'Channels';
|
||
|
||
@override
|
||
String get storeCategoryWeb => 'Web';
|
||
|
||
@override
|
||
String get storeCategoryOrchestrator => 'Orchestration';
|
||
|
||
@override
|
||
String storeNResults(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 's',
|
||
one: '',
|
||
);
|
||
return '$n result$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get storeReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get storeTodayBadge => 'TODAY';
|
||
|
||
@override
|
||
String get storeTodayDeck => 'From the F∆I editor';
|
||
|
||
@override
|
||
String get storeTodayDismissTooltip => 'Hide for this session';
|
||
|
||
@override
|
||
String get storePillInstalled => 'installed';
|
||
|
||
@override
|
||
String get storePillUpdate => 'update';
|
||
|
||
@override
|
||
String storeUpdateButton(String version) {
|
||
return 'Update to $version';
|
||
}
|
||
|
||
@override
|
||
String storeUpdateTooltip(String installed, String best) {
|
||
return 'Installed $installed — store has v$best';
|
||
}
|
||
|
||
@override
|
||
String get storeNoTagline => '(no tagline)';
|
||
|
||
@override
|
||
String get storeUninstallTitle => 'Uninstall module?';
|
||
|
||
@override
|
||
String storeUninstallBody(String name) {
|
||
return 'Removes $name from this hub. Flows that reference it will fail at the next run.';
|
||
}
|
||
|
||
@override
|
||
String storeInstalledToast(String name, String version) {
|
||
return '$name v$version installed.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallFailedToast(String error) {
|
||
return 'Install failed: $error';
|
||
}
|
||
|
||
@override
|
||
String storeUninstalledToast(String name, String version) {
|
||
return '$name v$version uninstalled.';
|
||
}
|
||
|
||
@override
|
||
String storeUninstallFailedToast(String error) {
|
||
return 'Uninstall failed: $error';
|
||
}
|
||
|
||
@override
|
||
String storeOpenBrowserFailed(String error) {
|
||
return 'Could not open browser: $error';
|
||
}
|
||
|
||
@override
|
||
String get storeSectionTags => 'Tags';
|
||
|
||
@override
|
||
String get storeSectionRequiredCapabilities => 'Required capabilities';
|
||
|
||
@override
|
||
String get storeSectionRequiredHostServices => 'Required host services';
|
||
|
||
@override
|
||
String get storeSectionScreenshots => 'Screenshots';
|
||
|
||
@override
|
||
String get storeSectionDocumentation => 'Documentation';
|
||
|
||
@override
|
||
String get storeSectionSource => 'Source';
|
||
|
||
@override
|
||
String get storeSectionPermissions => 'Declared permissions';
|
||
|
||
@override
|
||
String get storeSectionDirectory => 'Module directory';
|
||
|
||
@override
|
||
String get storeSectionPermissionsNone => '(none — pure-computation module)';
|
||
|
||
@override
|
||
String get storeInstallingButton => 'Installing…';
|
||
|
||
@override
|
||
String get storeNotInstallable => 'Not installable';
|
||
|
||
@override
|
||
String storeNotInstallableTooltip(String status) {
|
||
return 'Status \"$status\" — install path not yet wired.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallProgressTitle(String name) {
|
||
return 'Installing $name';
|
||
}
|
||
|
||
@override
|
||
String get storeInstallProgressBody => 'Fetching, verifying, unpacking…';
|
||
|
||
@override
|
||
String get storeLoadDocs => 'Load documentation';
|
||
|
||
@override
|
||
String get storeDocsHint =>
|
||
'README rendered inline; uses the hub\'s registry token when needed.';
|
||
|
||
@override
|
||
String get storeDocsFetching => 'Fetching README…';
|
||
|
||
@override
|
||
String get storeOpenRepoButton => 'Open repository in browser';
|
||
|
||
@override
|
||
String get storeDocsErrorNotFound =>
|
||
'This module is not in the hub\'s store index.';
|
||
|
||
@override
|
||
String get storeDocsErrorNoDocs =>
|
||
'No repository URL is recorded for this module.';
|
||
|
||
@override
|
||
String get storeDocsErrorAuth =>
|
||
'The registry requires authentication to fetch this README. Set FAI_REGISTRY_TOKEN in the daemon\'s environment and restart the hub.';
|
||
|
||
@override
|
||
String storeDocsErrorNetwork(String detail) {
|
||
return 'Network error while fetching the README. $detail';
|
||
}
|
||
|
||
@override
|
||
String get storeDocsErrorParse => 'README is not valid UTF-8.';
|
||
|
||
@override
|
||
String get storeDocsErrorGeneric => 'Could not load README.';
|
||
|
||
@override
|
||
String get storeSourceLabel => 'Source';
|
||
|
||
@override
|
||
String get storeSourceAll => 'All sources';
|
||
|
||
@override
|
||
String get storeSourceNative => 'Native';
|
||
|
||
@override
|
||
String get storeSourceMcp => 'MCP';
|
||
|
||
@override
|
||
String get storeSourceN8n => 'n8n';
|
||
|
||
@override
|
||
String get storeProvenanceNative => 'native';
|
||
|
||
@override
|
||
String storeProvenanceMcp(String provider) {
|
||
return 'mcp · $provider';
|
||
}
|
||
|
||
@override
|
||
String storeProvenanceN8n(String provider) {
|
||
return 'n8n · $provider';
|
||
}
|
||
|
||
@override
|
||
String get storeRecommendedTitle => 'Add a public source — one click';
|
||
|
||
@override
|
||
String get storeRecommendedBody =>
|
||
'Curated MCP servers reachable over HTTPS. No subprocess, no API key, no Node. Federated capabilities appear in the store immediately.';
|
||
|
||
@override
|
||
String get storeRecommendedAddTooltip => 'Add and discover';
|
||
|
||
@override
|
||
String get storeRecommendedAdding => 'Adding…';
|
||
|
||
@override
|
||
String get storeRecommendedDeepWikiTagline =>
|
||
'GitHub repo documentation search (AI-powered)';
|
||
|
||
@override
|
||
String get storeRecommendedSemgrepTagline =>
|
||
'Security scanning for code vulnerabilities';
|
||
|
||
@override
|
||
String storeProviderAddedToast(String name, int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'capabilities',
|
||
one: 'capability',
|
||
);
|
||
return 'Added $name — $n federated $_temp0.';
|
||
}
|
||
|
||
@override
|
||
String storeProviderAddedZeroToast(String name) {
|
||
return '$name registered, but the server returned no capabilities yet. Open Settings → MCP Clients to retry discovery or check the server.';
|
||
}
|
||
|
||
@override
|
||
String storeProviderAddFailed(String name, String error) {
|
||
return 'Could not add $name: $error';
|
||
}
|
||
|
||
@override
|
||
String get auditTitle => 'Audit';
|
||
|
||
@override
|
||
String get auditNoEvents => 'No events yet';
|
||
|
||
@override
|
||
String get auditNoEventsHint =>
|
||
'Run a flow to populate the audit stream.\nEvents appear here within seconds.';
|
||
|
||
@override
|
||
String get auditFilterAll => 'all';
|
||
|
||
@override
|
||
String get auditFilterFlow => 'flow';
|
||
|
||
@override
|
||
String get auditFilterStep => 'step';
|
||
|
||
@override
|
||
String get auditFilterModule => 'module';
|
||
|
||
@override
|
||
String get auditClearLogTooltip => 'Clear log (local/dev channels only)';
|
||
|
||
@override
|
||
String auditClearedToast(int n, String channel) {
|
||
return 'Cleared $n events on channel \"$channel\". Chain reseeded with marker.';
|
||
}
|
||
|
||
@override
|
||
String auditClearFailed(String detail) {
|
||
return 'Clear failed: $detail';
|
||
}
|
||
|
||
@override
|
||
String get auditExplain => 'Explain';
|
||
|
||
@override
|
||
String get auditReask => 'Re-ask';
|
||
|
||
@override
|
||
String get auditAsking => 'Asking…';
|
||
|
||
@override
|
||
String get auditSystemAi => 'SYSTEM AI';
|
||
|
||
@override
|
||
String get auditCachedPill => 'cached';
|
||
|
||
@override
|
||
String auditOriginalLatency(int ms) {
|
||
return 'orig $ms ms';
|
||
}
|
||
|
||
@override
|
||
String auditLatency(int ms) {
|
||
return '$ms ms';
|
||
}
|
||
|
||
@override
|
||
String get auditRegenerateTooltip =>
|
||
'Regenerate — skip cache, ask the model again';
|
||
|
||
@override
|
||
String auditLiveStatus(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'events',
|
||
one: 'event',
|
||
);
|
||
return 'live · polling 2s · $n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String auditDisconnected(String error) {
|
||
return 'disconnected · $error';
|
||
}
|
||
|
||
@override
|
||
String get auditHashChainVerified => 'hash chain verified';
|
||
|
||
@override
|
||
String get auditDetailHeader => 'DETAIL';
|
||
|
||
@override
|
||
String get auditAskingFull => 'Asking the configured System AI…';
|
||
|
||
@override
|
||
String get auditFixLabel => 'FIX';
|
||
|
||
@override
|
||
String auditCachedTooltipKnown(String at, String hits) {
|
||
return 'Served from the local cache. Originally generated on $at$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipUnknown(String hits) {
|
||
return 'Served from the local cache. Originally generated at unknown time$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipHits(int n) {
|
||
return ' · $n hits';
|
||
}
|
||
|
||
@override
|
||
String get auditConfigureSystemAi =>
|
||
'Configure System AI in Settings (Cmd+,)';
|
||
|
||
@override
|
||
String get auditClearDialogTitle => 'Clear audit log?';
|
||
|
||
@override
|
||
String get auditClearDialogBody =>
|
||
'Wipes every audit event on the active channel and seeds a fresh chain.reset marker carrying reviewer + reason. Refused on beta / production. Irreversible.';
|
||
|
||
@override
|
||
String get auditClearReviewerLabel => 'Reviewer';
|
||
|
||
@override
|
||
String get auditClearReasonLabel => 'Reason (recorded in chain.reset marker)';
|
||
|
||
@override
|
||
String get auditClearReasonHelper => 'Required — auditors will read this.';
|
||
|
||
@override
|
||
String get auditClearLogButton => 'Clear log';
|
||
|
||
@override
|
||
String get modulesTitle => 'Modules';
|
||
|
||
@override
|
||
String get modulesNoneTitle => 'No modules yet';
|
||
|
||
@override
|
||
String get modulesNoneHint =>
|
||
'Run `fai install <capability-name>` or check ~/.fai/modules/.';
|
||
|
||
@override
|
||
String get modulesReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get modulesRecentActivity => 'RECENT ACTIVITY';
|
||
|
||
@override
|
||
String modulesRecentActivityHint(int n) {
|
||
return 'last $n install/uninstall events from the audit log';
|
||
}
|
||
|
||
@override
|
||
String get modulesActivityInstalled => 'installed';
|
||
|
||
@override
|
||
String get modulesActivityUninstalled => 'uninstalled';
|
||
|
||
@override
|
||
String get modulesCapabilitiesLabel => 'Capabilities';
|
||
|
||
@override
|
||
String get modulesUninstallTitle => 'Uninstall module?';
|
||
|
||
@override
|
||
String modulesUninstallBody(String name, String version) {
|
||
return 'Removes $name v$version from this hub. Flows that reference it will fail at the next run. A `module.uninstalled` audit event is recorded.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstalledToast(String name, String version) {
|
||
return 'Uninstalled $name v$version.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstallFailed(String error) {
|
||
return 'Uninstall failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get modulesUninstalling => 'Uninstalling…';
|
||
|
||
@override
|
||
String moduleSheetFailedToLoad(String error) {
|
||
return 'Failed to load: $error';
|
||
}
|
||
|
||
@override
|
||
String get moduleSheetCapabilities => 'Capabilities';
|
||
|
||
@override
|
||
String get moduleSheetPermissions => 'Declared permissions';
|
||
|
||
@override
|
||
String get moduleSheetNoPermissions => '(none — pure-computation module)';
|
||
|
||
@override
|
||
String get flowsTitle => 'Flows';
|
||
|
||
@override
|
||
String get flowsReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get flowsNoneTitle => 'No saved flows';
|
||
|
||
@override
|
||
String get flowsNoneHint =>
|
||
'Save a flow with `fai admin flows save <name> <flow.yaml>` and it shows up here.';
|
||
|
||
@override
|
||
String flowsRunDialogTitle(String name) {
|
||
return 'Run $name';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunDialogBody =>
|
||
'One field per declared input. Pick a file for bytes-shaped inputs; type plain text for the rest. The Run button enables when every required input is set.';
|
||
|
||
@override
|
||
String get flowsLoadingDefinition => 'Loading inputs…';
|
||
|
||
@override
|
||
String get flowsDefinitionFailed => 'Could not load flow definition';
|
||
|
||
@override
|
||
String get flowsNoInputs =>
|
||
'This flow declares no inputs. Click Run to start.';
|
||
|
||
@override
|
||
String get flowsTypeBytesPick => 'Choose file…';
|
||
|
||
@override
|
||
String get flowsTypeBytesChange => 'Change file';
|
||
|
||
@override
|
||
String get flowsTypeBytesNoFile => 'No file selected';
|
||
|
||
@override
|
||
String flowsTypeBytesSize(int n) {
|
||
return '$n bytes';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunErrorTitle => 'Flow run failed';
|
||
|
||
@override
|
||
String flowsFileReadFailed(String path, String error) {
|
||
return 'Could not read \"$path\": $error';
|
||
}
|
||
|
||
@override
|
||
String get flowsMissingModulesLabel => 'Needs:';
|
||
|
||
@override
|
||
String get flowsRunDisabledTooltip => 'Install the missing modules first.';
|
||
|
||
@override
|
||
String flowsInstallAllButton(int n) {
|
||
return 'Install all ($n)';
|
||
}
|
||
|
||
@override
|
||
String get flowsInstallPillTooltip => 'Click to install';
|
||
|
||
@override
|
||
String get flowsInstallDepsTitle => 'Install dependencies';
|
||
|
||
@override
|
||
String get flowsInstallDepsBody =>
|
||
'Walking through the missing modules in order. Existing installs are left alone.';
|
||
|
||
@override
|
||
String get flowsInstallStatusPending => 'Pending';
|
||
|
||
@override
|
||
String get flowsInstallStatusInstalling => 'Installing…';
|
||
|
||
@override
|
||
String flowsInstallStatusDone(String version) {
|
||
return 'Installed v$version';
|
||
}
|
||
|
||
@override
|
||
String get flowsInstallStatusFailed => 'Failed';
|
||
|
||
@override
|
||
String flowsInstallStatusFailedDetail(String error) {
|
||
return '$error';
|
||
}
|
||
|
||
@override
|
||
String get flowsInstallDepsAllDone => 'All dependencies installed.';
|
||
|
||
@override
|
||
String flowsInstallDepsAnyFailed(int ok, int failed) {
|
||
return '$ok installed, $failed failed.';
|
||
}
|
||
|
||
@override
|
||
String get flowsInstallAuthWallButton => 'Add registry token';
|
||
|
||
@override
|
||
String get flowsOpenInEditorTooltip =>
|
||
'Open the YAML file in your default editor';
|
||
|
||
@override
|
||
String flowsOpenInEditorFailed(String error) {
|
||
return 'Could not open file: $error';
|
||
}
|
||
|
||
@override
|
||
String get registryCredentialsHeader => 'REGISTRY CREDENTIALS';
|
||
|
||
@override
|
||
String get registryCredentialsBlurb =>
|
||
'Token used to download .fai modules from a registry behind a signin wall (Forgejo, GitHub-private). Stored at ~/.fai/registry-token, mode 0600. The FAI_REGISTRY_TOKEN env var still wins when set.';
|
||
|
||
@override
|
||
String registryTokenStatusConfigured(int chars) {
|
||
return 'Configured ($chars chars)';
|
||
}
|
||
|
||
@override
|
||
String get registryTokenStatusNotSet => 'Not set';
|
||
|
||
@override
|
||
String get registryTokenFieldLabel => 'Token';
|
||
|
||
@override
|
||
String get registryTokenFieldHint =>
|
||
'Paste your Forgejo or GitHub personal access token';
|
||
|
||
@override
|
||
String get registryTokenSaveButton => 'Save';
|
||
|
||
@override
|
||
String get registryTokenClearButton => 'Clear';
|
||
|
||
@override
|
||
String get registryTokenStorageHint =>
|
||
'Saved locally to ~/.fai/registry-token. Never sent to a remote service.';
|
||
|
||
@override
|
||
String get registryTokenSavedToast => 'Registry token saved.';
|
||
|
||
@override
|
||
String get registryTokenClearedToast => 'Registry token cleared.';
|
||
|
||
@override
|
||
String registryTokenSaveFailedToast(String error) {
|
||
return 'Could not save: $error';
|
||
}
|
||
|
||
@override
|
||
String get hubAuthTokenHeader => 'HUB AUTHENTICATION';
|
||
|
||
@override
|
||
String get hubAuthTokenBlurb =>
|
||
'Bearer token used to authenticate Studio against a hub that has auth.tokens: configured (RBAC Level 2). Stored at ~/.fai/hub-auth-token, mode 0600. Studio sends it as Authorization: Bearer on every gRPC call.';
|
||
|
||
@override
|
||
String hubAuthTokenStatusConfigured(int chars) {
|
||
return 'Configured ($chars chars)';
|
||
}
|
||
|
||
@override
|
||
String get hubAuthTokenStatusNotSet => 'Not set (anonymous)';
|
||
|
||
@override
|
||
String get hubAuthTokenFieldLabel => 'Token';
|
||
|
||
@override
|
||
String get hubAuthTokenFieldHint =>
|
||
'Paste a token from the hub operator\'s auth.tokens entry';
|
||
|
||
@override
|
||
String get hubAuthTokenSaveButton => 'Save';
|
||
|
||
@override
|
||
String get hubAuthTokenClearButton => 'Clear';
|
||
|
||
@override
|
||
String get hubAuthTokenStorageHint =>
|
||
'Saved locally to ~/.fai/hub-auth-token. Studio reconnects after save so the new token takes effect immediately.';
|
||
|
||
@override
|
||
String get hubAuthTokenSavedToast => 'Hub auth token saved.';
|
||
|
||
@override
|
||
String get hubAuthTokenClearedToast => 'Hub auth token cleared.';
|
||
|
||
@override
|
||
String hubAuthTokenSaveFailedToast(String error) {
|
||
return 'Could not save: $error';
|
||
}
|
||
|
||
@override
|
||
String get storeAdvisoryVersionTooltip =>
|
||
'Federated upstream service — version is advisory; the upstream may break compatibility without bumping it.';
|
||
|
||
@override
|
||
String get maintenanceHeader => 'HUB MAINTENANCE';
|
||
|
||
@override
|
||
String get maintenanceResetBlurb =>
|
||
'Wipe operator state and start over with a clean hub. Stops every running daemon, atomically backs ~/.fai/ up, then recreates it with the binary, channel state, MCP / n8n / system-AI config, and registry token preserved. Restore by moving the backup directory back.';
|
||
|
||
@override
|
||
String get maintenanceKeepModulesTitle => 'Keep installed modules';
|
||
|
||
@override
|
||
String get maintenanceKeepModulesSubtitle =>
|
||
'Default behaviour wipes ~/.fai/modules/ so a fresh install can verify the module-fetch path end-to-end.';
|
||
|
||
@override
|
||
String get maintenanceKeepDataTitle => 'Keep audit log + saved flows';
|
||
|
||
@override
|
||
String get maintenanceKeepDataSubtitle =>
|
||
'Default behaviour wipes ~/.fai/data/ so the audit chain restarts from a fresh genesis and the bundled sample flows re-import on first daemon start.';
|
||
|
||
@override
|
||
String get maintenanceResetButton => 'Reset hub state';
|
||
|
||
@override
|
||
String get maintenanceResetInProgress => 'Resetting…';
|
||
|
||
@override
|
||
String get maintenanceResetConfirmTitle => 'Reset hub state?';
|
||
|
||
@override
|
||
String get maintenanceResetConfirmBody =>
|
||
'This stops every daemon, moves ~/.fai/ to a timestamped backup, and starts fresh. The backup is fully restorable. Continue?';
|
||
|
||
@override
|
||
String get maintenanceResetConfirmButton => 'Reset';
|
||
|
||
@override
|
||
String get welcomeChecklistAllSetTitle => 'You\'re set up.';
|
||
|
||
@override
|
||
String get welcomeChecklistAllSetBody => 'Three threads to pull on next:';
|
||
|
||
@override
|
||
String get welcomeChecklistNextAuditTitle => 'Read the audit log';
|
||
|
||
@override
|
||
String get welcomeChecklistNextAuditBody =>
|
||
'Every install, flow run, and approval lives in the hash-chained log. Open the Audit tab to see what your hub has been up to.';
|
||
|
||
@override
|
||
String get welcomeChecklistNextAuditButton => 'Open Audit';
|
||
|
||
@override
|
||
String get welcomeChecklistNextTodayTitle => 'Set up the daily Today story';
|
||
|
||
@override
|
||
String get welcomeChecklistNextTodayBody =>
|
||
'Run tools/today/propose.sh on a cron and the editorial card on the store auto-fills with operator-curated narratives.';
|
||
|
||
@override
|
||
String get welcomeChecklistNextTodayButton => 'Open Today docs';
|
||
|
||
@override
|
||
String get welcomeChecklistNextModuleTitle => 'Build your own module';
|
||
|
||
@override
|
||
String get welcomeChecklistNextModuleBody =>
|
||
'Generate a Rust+WASM scaffold with `fai new module <name>`. The module-sdk handles the WIT plumbing; you write a typed invoke.';
|
||
|
||
@override
|
||
String get welcomeChecklistNextModuleButton => 'Read the docs';
|
||
|
||
@override
|
||
String get auditGroupToday => 'TODAY';
|
||
|
||
@override
|
||
String get auditGroupYesterday => 'YESTERDAY';
|
||
|
||
@override
|
||
String get auditGroupThisWeek => 'EARLIER THIS WEEK';
|
||
|
||
@override
|
||
String get auditGroupOlder => 'OLDER';
|
||
|
||
@override
|
||
String get auditEventViewFlowRun => 'View flow run';
|
||
|
||
@override
|
||
String auditFlowRunDialogTitle(String flow) {
|
||
return 'Flow run · $flow';
|
||
}
|
||
|
||
@override
|
||
String auditFlowRunDialogSubtitle(int n, String execution) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'events',
|
||
one: 'event',
|
||
);
|
||
return '$n $_temp0 for execution $execution';
|
||
}
|
||
|
||
@override
|
||
String get approvalsSelectAll => 'Select all';
|
||
|
||
@override
|
||
String get approvalsClearSelection => 'Clear';
|
||
|
||
@override
|
||
String approvalsBatchSelected(int n) {
|
||
return '$n selected';
|
||
}
|
||
|
||
@override
|
||
String get approvalsBatchApprove => 'Approve all';
|
||
|
||
@override
|
||
String get approvalsBatchReject => 'Reject all';
|
||
|
||
@override
|
||
String approvalsBatchApproveDoneToast(int n) {
|
||
return '$n approvals approved.';
|
||
}
|
||
|
||
@override
|
||
String approvalsBatchRejectDoneToast(int n) {
|
||
return '$n approvals rejected.';
|
||
}
|
||
|
||
@override
|
||
String approvalsBatchPartialFailure(int ok, int failed) {
|
||
return '$ok done, $failed failed.';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunButton => 'Run';
|
||
|
||
@override
|
||
String flowsRunningTitle(String name) {
|
||
return 'Running $name';
|
||
}
|
||
|
||
@override
|
||
String flowsResultTitle(String name) {
|
||
return '$name — result';
|
||
}
|
||
|
||
@override
|
||
String flowsErrorTitle(String name) {
|
||
return '$name — failed';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunning => 'Flow running…';
|
||
|
||
@override
|
||
String get flowsNoOutputs => 'Flow completed with no declared outputs.';
|
||
|
||
@override
|
||
String get errGeneric => 'Something went wrong.';
|
||
|
||
@override
|
||
String get errInvalidArgument => 'Invalid input.';
|
||
|
||
@override
|
||
String get errInvalidArgumentHint => 'Check the form values and try again.';
|
||
|
||
@override
|
||
String get errNotFound => 'Not found.';
|
||
|
||
@override
|
||
String get errNotFoundHint =>
|
||
'The item you asked for isn\'t here — it may have been removed or never existed.';
|
||
|
||
@override
|
||
String get errAlreadyExists => 'Already exists.';
|
||
|
||
@override
|
||
String get errPermissionDenied => 'Permission denied.';
|
||
|
||
@override
|
||
String get errPermissionDeniedHint =>
|
||
'The hub\'s operator policy blocks this action. Check `~/.fai/config.yaml`.';
|
||
|
||
@override
|
||
String get errFailedPrecondition => 'Setup issue blocked this.';
|
||
|
||
@override
|
||
String get errFailedPreconditionHint =>
|
||
'The hub couldn\'t proceed because something it needs isn\'t ready. The detail below explains what.';
|
||
|
||
@override
|
||
String get errInternal => 'Unexpected internal error.';
|
||
|
||
@override
|
||
String get errInternalHint =>
|
||
'Check the hub logs at `~/.fai/logs/`. If this repeats, please report it.';
|
||
|
||
@override
|
||
String get errUnavailable => 'Hub not reachable.';
|
||
|
||
@override
|
||
String get errUnavailableHint =>
|
||
'Make sure `fai serve` (or `fai daemon start`) is running and the daemon endpoint matches Studio\'s settings.';
|
||
|
||
@override
|
||
String get errUnauthenticated => 'Authentication required.';
|
||
|
||
@override
|
||
String get errUnauthenticatedHint =>
|
||
'Set `FAI_REGISTRY_TOKEN` or sign in through Settings before retrying.';
|
||
|
||
@override
|
||
String get errCopyDetail => 'Copy detail';
|
||
|
||
@override
|
||
String get errDetailCopied => 'Detail copied to clipboard.';
|
||
|
||
@override
|
||
String get flowsOutputUnknown => 'Output payload variant not recognised.';
|
||
|
||
@override
|
||
String get flowsOutputBytesUnknownMime => 'binary';
|
||
|
||
@override
|
||
String get flowsOutputSaveAs => 'Save as…';
|
||
|
||
@override
|
||
String get flowsOutputSaveAsTitle => 'Save flow output';
|
||
|
||
@override
|
||
String flowsOutputSavedAt(String path) {
|
||
return 'Saved to $path';
|
||
}
|
||
|
||
@override
|
||
String flowsOutputSaveFailed(String error) {
|
||
return 'Save failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get flowsOutputOpen => 'Open';
|
||
|
||
@override
|
||
String flowsOutputOpenFailed(String error) {
|
||
return 'Open failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get approvalsTitle => 'Approvals';
|
||
|
||
@override
|
||
String get approvalsTabPending => 'Pending';
|
||
|
||
@override
|
||
String get approvalsTabHistory => 'History';
|
||
|
||
@override
|
||
String get approvalsInboxZero => 'Inbox zero';
|
||
|
||
@override
|
||
String get approvalsInboxHint =>
|
||
'All caught up. New `system.approval@^0` steps land here automatically.';
|
||
|
||
@override
|
||
String get approvalsReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get approvalsPillPending => 'pending';
|
||
|
||
@override
|
||
String get approvalsPillApproved => 'approved';
|
||
|
||
@override
|
||
String get approvalsPillRejected => 'rejected';
|
||
|
||
@override
|
||
String get approvalsPillExpired => 'expired';
|
||
|
||
@override
|
||
String get approvalsPayloadPreview => 'PAYLOAD PREVIEW';
|
||
|
||
@override
|
||
String get approvalsApproveButton => 'Approve';
|
||
|
||
@override
|
||
String get approvalsRejectButton => 'Reject';
|
||
|
||
@override
|
||
String get approvalsRejectDialogTitle => 'Reject approval';
|
||
|
||
@override
|
||
String get approvalsRejectReasonLabel => 'Reason (recorded in audit log)';
|
||
|
||
@override
|
||
String approvalsApprovedToast(String flow, String step) {
|
||
return 'approved · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectedToast(String flow, String step) {
|
||
return 'rejected · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsApproveFailed(String error) {
|
||
return 'approve failed: $error';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectFailed(String error) {
|
||
return 'reject failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get approvalsHistoryEmpty => 'No history yet';
|
||
|
||
@override
|
||
String get approvalsHistoryEmptyHint =>
|
||
'Decided approvals (approved / rejected / expired) appear here.\nThe audit log keeps the full hash-chained record.';
|
||
|
||
@override
|
||
String get approvalsDialogDecided => 'decided';
|
||
|
||
@override
|
||
String get approvalsDialogCreated => 'created';
|
||
|
||
@override
|
||
String get approvalsDialogReason => 'reason';
|
||
|
||
@override
|
||
String get approvalsDialogPrompt => 'PROMPT';
|
||
|
||
@override
|
||
String approvalsExpiresIn(int minutes) {
|
||
return '${minutes}m';
|
||
}
|
||
|
||
@override
|
||
String approvalsExpiresInHours(int hours) {
|
||
return '${hours}h';
|
||
}
|
||
|
||
@override
|
||
String get doctorTitle => 'Doctor';
|
||
|
||
@override
|
||
String get doctorSummaryModules => 'Modules';
|
||
|
||
@override
|
||
String get doctorSummaryApprovals => 'Approvals';
|
||
|
||
@override
|
||
String get doctorSummaryAudit => 'Audit';
|
||
|
||
@override
|
||
String get doctorSummaryServices => 'Services';
|
||
|
||
@override
|
||
String doctorSummaryCapabilities(int n) {
|
||
return '$n capabilities';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryPending => 'pending';
|
||
|
||
@override
|
||
String doctorSummaryChain(int verified, int total) {
|
||
return '$verified/$total chain';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryDeclared => 'declared';
|
||
|
||
@override
|
||
String doctorModulesPanelSummary(int n, int m) {
|
||
return '$n modules · $m capabilities';
|
||
}
|
||
|
||
@override
|
||
String get doctorApprovalsNone => 'No pending approvals';
|
||
|
||
@override
|
||
String doctorApprovalsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: '$n approvals awaiting review',
|
||
one: '1 approval awaiting review',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get doctorApprovalsAttentionPill => 'attention';
|
||
|
||
@override
|
||
String get doctorServicesEmpty => 'No host services declared';
|
||
|
||
@override
|
||
String get doctorServicesEmptyHint =>
|
||
'add to ~/.fai/config.yaml under services:';
|
||
|
||
@override
|
||
String get doctorPillLoaded => 'loaded';
|
||
|
||
@override
|
||
String get doctorPillEmpty => 'empty';
|
||
|
||
@override
|
||
String get doctorRecheckTooltip => 'Re-check';
|
||
|
||
@override
|
||
String get doctorEventLogSection => 'Event log';
|
||
|
||
@override
|
||
String get doctorModulesApprovalsSection => 'Modules & approvals';
|
||
|
||
@override
|
||
String get doctorHostServicesSection => 'Host services';
|
||
|
||
@override
|
||
String get doctorDaemonFilesSection => 'Daemon files';
|
||
|
||
@override
|
||
String get doctorDaemonControlSection => 'Daemon control';
|
||
|
||
@override
|
||
String get doctorChainIntact => 'Hash chain intact';
|
||
|
||
@override
|
||
String doctorChainIntactDetail(int n) {
|
||
return '$n events · prev_event_sha256 verified end-to-end';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainTampered => 'Tampering detected';
|
||
|
||
@override
|
||
String doctorChainTamperedDetail(int verified, int total, String id) {
|
||
return '$verified of $total verified before mismatch at $id';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainPillOk => 'WORM-1';
|
||
|
||
@override
|
||
String get doctorChainPillTamper => 'TAMPER';
|
||
|
||
@override
|
||
String get doctorVerifyNow => 'Verify now';
|
||
|
||
@override
|
||
String get doctorRestart => 'Restart';
|
||
|
||
@override
|
||
String get doctorStart => 'Start';
|
||
|
||
@override
|
||
String get doctorStop => 'Stop';
|
||
|
||
@override
|
||
String get doctorStatusAction => 'Status';
|
||
|
||
@override
|
||
String doctorRunningOn(String name, String endpoint) {
|
||
return 'Running on $name: $endpoint';
|
||
}
|
||
|
||
@override
|
||
String doctorStoppedOn(String name) {
|
||
return '$name daemon stopped';
|
||
}
|
||
|
||
@override
|
||
String get doctorStatusUnknown => 'Daemon status: …';
|
||
|
||
@override
|
||
String get doctorPillRunning => 'running';
|
||
|
||
@override
|
||
String get doctorPillStopped => 'stopped';
|
||
|
||
@override
|
||
String get doctorDaemonControlHint =>
|
||
'Studio shells out to the platform binary — mirrors `fai daemon …` exactly so the CLI and UI stay in lockstep.';
|
||
|
||
@override
|
||
String get doctorDaemonControlWorking => 'Working…';
|
||
|
||
@override
|
||
String get doctorPathLog => 'Log';
|
||
|
||
@override
|
||
String get doctorPathConfig => 'Config';
|
||
|
||
@override
|
||
String get doctorPathDb => 'Audit DB';
|
||
|
||
@override
|
||
String get doctorPathModules => 'Modules dir';
|
||
|
||
@override
|
||
String get doctorPathFlows => 'Flows dir';
|
||
|
||
@override
|
||
String get doctorPathPid => 'PID file';
|
||
|
||
@override
|
||
String get doctorPathsEmpty =>
|
||
'Daemon did not report file paths. Update the running hub via `fai daemon restart`.';
|
||
|
||
@override
|
||
String doctorOpenError(String detail) {
|
||
return 'Could not open: $detail';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateAvailable(String version) {
|
||
return 'Update available — $version';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateBody(String channel, String version) {
|
||
return 'Channel $channel now offers $version. Apply via the button — Studio shells out to `fai update apply --channel $channel`.';
|
||
}
|
||
|
||
@override
|
||
String get doctorUpdateUnreachable => 'Release host unreachable';
|
||
|
||
@override
|
||
String doctorUpdateUnreachableBody(String channel) {
|
||
return 'Could not contact the release feed for $channel.';
|
||
}
|
||
|
||
@override
|
||
String doctorReleaseNotes(String url) {
|
||
return 'notes: $url';
|
||
}
|
||
|
||
@override
|
||
String get doctorPillNew => 'new';
|
||
|
||
@override
|
||
String get doctorPillOffline => 'offline';
|
||
|
||
@override
|
||
String get doctorApplyUpdate => 'Apply update';
|
||
|
||
@override
|
||
String get doctorApplying => 'Applying…';
|
||
|
||
@override
|
||
String get doctorApplyDone =>
|
||
'Update applied. Restart Studio to see the new daemon version.';
|
||
|
||
@override
|
||
String get mcpHeader => 'MCP CLIENTS';
|
||
|
||
@override
|
||
String get mcpHint =>
|
||
'External MCP servers federate their tools as `mcp.<server>.<tool>` capabilities. Configure once, see them in the Store.';
|
||
|
||
@override
|
||
String get mcpEmpty => 'No MCP servers configured. Click + to add one.';
|
||
|
||
@override
|
||
String get n8nHeader => 'N8N ENDPOINTS';
|
||
|
||
@override
|
||
String get n8nHint =>
|
||
'Active n8n workflows surface as `n8n.<endpoint>.<slug>` capabilities. Configure once, see them in the Store.';
|
||
|
||
@override
|
||
String get n8nEmpty => 'No n8n endpoints configured. Click + to add one.';
|
||
|
||
@override
|
||
String get hubUnreachable => 'Hub unreachable';
|
||
|
||
@override
|
||
String get hubUnreachableHint => 'Start the hub with `fai serve`.';
|
||
|
||
@override
|
||
String get languageEnglish => 'English';
|
||
|
||
@override
|
||
String get languageGerman => 'Deutsch';
|
||
|
||
@override
|
||
String get searchHint => 'Jump anywhere — modules, store, flows, pages…';
|
||
|
||
@override
|
||
String get searchIndexing => 'Indexing…';
|
||
|
||
@override
|
||
String get searchNoMatches => 'No matches.';
|
||
|
||
@override
|
||
String get searchHintNavigate => '↑↓ navigate';
|
||
|
||
@override
|
||
String get searchHintOpen => 'enter open';
|
||
|
||
@override
|
||
String get searchHintClose => 'esc close';
|
||
|
||
@override
|
||
String get searchGroupPages => 'Pages';
|
||
|
||
@override
|
||
String get searchGroupModules => 'Modules';
|
||
|
||
@override
|
||
String get searchGroupStore => 'Store';
|
||
|
||
@override
|
||
String get searchGroupFlows => 'Flows';
|
||
|
||
@override
|
||
String get searchSettingsLabel => 'Settings';
|
||
|
||
@override
|
||
String searchPageHint(int n) {
|
||
return 'page · ⌘$n';
|
||
}
|
||
|
||
@override
|
||
String get searchSettingsHint => 'hub endpoint, channels, system AI · ⌘;';
|
||
|
||
@override
|
||
String searchInstalledModuleHint(String version) {
|
||
return 'installed module · v$version';
|
||
}
|
||
|
||
@override
|
||
String get searchStoreUncategorized => 'uncategorized';
|
||
|
||
@override
|
||
String searchStoreHintWithTagline(String tagline) {
|
||
return 'store · $tagline';
|
||
}
|
||
|
||
@override
|
||
String searchStoreHintWithCategory(String category) {
|
||
return 'store · $category';
|
||
}
|
||
|
||
@override
|
||
String get searchSavedFlowHint => 'saved flow';
|
||
|
||
@override
|
||
String get systemAiTitle => 'System AI';
|
||
|
||
@override
|
||
String get systemAiIntro =>
|
||
'The hub-internal LLM the platform itself uses for inline failure explanations and operator help. Off by default; configure here. See docs/architecture/system-ai.md for what crosses the wire.';
|
||
|
||
@override
|
||
String get systemAiProviderLabel => 'Provider';
|
||
|
||
@override
|
||
String get systemAiEndpointLabel => 'Endpoint URL (up to /v1)';
|
||
|
||
@override
|
||
String get systemAiApiKeyRequired => 'API key env var (required)';
|
||
|
||
@override
|
||
String get systemAiApiKeyOptional => 'API key env var (optional)';
|
||
|
||
@override
|
||
String systemAiApiKeyDisclaimer(String name) {
|
||
return 'Studio never reads or stores the key value — only its env-var name. The hub reads `\$$name` at request time.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiTestConnection => 'Test connection';
|
||
|
||
@override
|
||
String get systemAiTesting => 'Testing…';
|
||
|
||
@override
|
||
String get systemAiSave => 'Save';
|
||
|
||
@override
|
||
String get systemAiPrivacyHeader => 'PRIVACY MODE';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffLabel => 'Off';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffDesc =>
|
||
'Feature disabled. No requests leave the hub.';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedLabel => 'Redacted';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedDesc =>
|
||
'Only event_type / error / module names. KRITIS-friendly default.';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullLabel => 'Full';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullDesc =>
|
||
'Includes the audit detail JSON (hash-only — no raw payloads).';
|
||
|
||
@override
|
||
String get systemAiConnectionOk => 'Connection ok';
|
||
|
||
@override
|
||
String get systemAiConnectionFailed => 'Connection failed';
|
||
|
||
@override
|
||
String systemAiReplyPrefix(String text) {
|
||
return 'Reply: $text';
|
||
}
|
||
|
||
@override
|
||
String get systemAiModelLabel => 'Model (required)';
|
||
|
||
@override
|
||
String get systemAiModelHintFallback =>
|
||
'model identifier the provider expects';
|
||
|
||
@override
|
||
String get systemAiModelHelperBase =>
|
||
'Required: pick from the list (Refresh) or type one.';
|
||
|
||
@override
|
||
String get systemAiModelHelperOllama =>
|
||
'Required: pick from the list (Refresh) or type one. Use Pull to download from Ollama.';
|
||
|
||
@override
|
||
String get systemAiRefresh => 'Refresh';
|
||
|
||
@override
|
||
String get systemAiPull => 'Pull';
|
||
|
||
@override
|
||
String get systemAiPulling => 'Pulling…';
|
||
|
||
@override
|
||
String systemAiCouldNotListModels(String error) {
|
||
return 'Could not list models: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiNoModelsOllama =>
|
||
'No models on the Ollama server yet. Type one above and click Pull.';
|
||
|
||
@override
|
||
String get systemAiNoModelsGeneric => 'Provider returned no models.';
|
||
|
||
@override
|
||
String get systemAiSuitabilityRecommended => 'recommended';
|
||
|
||
@override
|
||
String get systemAiSuitabilityBalanced => 'balanced';
|
||
|
||
@override
|
||
String get systemAiSuitabilitySmall => 'small — quality may be limited';
|
||
|
||
@override
|
||
String get systemAiSuitabilityLarge => 'large — slower';
|
||
|
||
@override
|
||
String get systemAiSuitabilityHuge => 'huge — likely too slow on a laptop';
|
||
|
||
@override
|
||
String get systemAiSuitabilityUnknown => 'size unknown';
|
||
|
||
@override
|
||
String systemAiHwDetected(String summary) {
|
||
return 'Detected: $summary';
|
||
}
|
||
|
||
@override
|
||
String systemAiHwReviewed(String date) {
|
||
return ' · curation reviewed $date';
|
||
}
|
||
|
||
@override
|
||
String systemAiLegendRecommended(String tier) {
|
||
return 'recommended for this hardware$tier';
|
||
}
|
||
|
||
@override
|
||
String get systemAiLegendBalanced => 'balanced (4-8B)';
|
||
|
||
@override
|
||
String get systemAiLegendSmallLarge =>
|
||
'small <3B / large 9-15B / above hardware';
|
||
|
||
@override
|
||
String get systemAiLegendHuge => 'huge >15B';
|
||
|
||
@override
|
||
String get systemAiLegendUnknown => 'size unknown';
|
||
|
||
@override
|
||
String systemAiCacheRow(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'explanations',
|
||
one: 'explanation',
|
||
);
|
||
return 'Cache: $n cached $_temp0. Identical prompts hit the cache; switching model or privacy mode flushes automatically.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiCacheClear => 'Clear';
|
||
|
||
@override
|
||
String systemAiCacheClearedToast(int n) {
|
||
return 'Cleared $n cached System-AI explanations.';
|
||
}
|
||
|
||
@override
|
||
String systemAiCacheClearFailed(String error) {
|
||
return 'Cache clear failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiPullEmptyError =>
|
||
'Type a model id (e.g. gemma3:4b) first.';
|
||
|
||
@override
|
||
String systemAiPullFailedError(String error) {
|
||
return 'Pull failed: $error';
|
||
}
|
||
|
||
@override
|
||
String storeProvenanceTemporal(String provider) {
|
||
return 'temporal · $provider';
|
||
}
|
||
|
||
@override
|
||
String get storeSourceTemporal => 'Temporal';
|
||
}
|