The switcher used to be embedded per page (Flows/Runs/Audit/
Approvals) — invisible on the other five pages and sitting in a
different corner depending on the page (persona review 2026-08-27,
consensus finding). It now lives ONCE in the sidebar, above the
destinations: active project/area always visible, opens the same
menu everywhere, Cmd+P from anywhere. The shell listens to the
workspace, so the sidebar endpoint label can no longer lag a
sealed switch until the next health tick.
Also in this rebuild:
* Stopped sealed areas ask before starting ("Start area X?") —
a context switch must never boot a hub daemon as a click
side-effect; running areas keep switching with one click.
* The switcher tooltip told a wrong scope ("filters this view") —
it now says the choice applies everywhere and stamps new runs.
* The aggregated sealed row explains itself in place (names can
reveal client identities) and links to the Settings toggle
(Settings dialog gained an initialCategory jump).
* The active entry carries a checkmark in the menu.
* The Cmd+K palette knows projects and areas, ranked by recent
use; sealed names honour the privacy setting — while hidden,
the palette offers the guarded picker instead of the names.
* The runs empty state names the active project filter as the
cause ("No runs in project X" + show-all action) instead of
claiming the feature is off.
Tests updated to the anchor and made hermetic (scriptable
projects on the fake hub, sealed-area fake); new coverage for the
checkmark, the why-line, and the start confirmation.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
3979 lines
105 KiB
Dart
3979 lines
105 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 errModuleDownload => 'Module download failed';
|
||
|
||
@override
|
||
String get errModuleDownloadHint =>
|
||
'The module\'s bundle URL is unreachable (status code below). The hub is running fine — fix the URL/host or choose another store.';
|
||
|
||
@override
|
||
String storeFromSource(String store) {
|
||
return 'from $store';
|
||
}
|
||
|
||
@override
|
||
String get guidedSetupTitle => 'Setup assistant';
|
||
|
||
@override
|
||
String get guidedSetupIntro =>
|
||
'Answer three questions and Ch∆In assembles a tailored config, module set and starter flow.';
|
||
|
||
@override
|
||
String get guidedSetupScenario => 'Scenario';
|
||
|
||
@override
|
||
String get guidedSetupIntent => 'Task';
|
||
|
||
@override
|
||
String get guidedSetupTarget => 'Where will it run?';
|
||
|
||
@override
|
||
String get guidedSetupApproval =>
|
||
'Require a human approval step before the AI step';
|
||
|
||
@override
|
||
String get guidedSetupDataLocal =>
|
||
'Data must stay local (air-gapped posture)';
|
||
|
||
@override
|
||
String get guidedSetupReviewHeading => 'This is the plan Ch∆In will apply:';
|
||
|
||
@override
|
||
String get guidedSetupApply => 'Apply setup';
|
||
|
||
@override
|
||
String get guidedSetupApplied =>
|
||
'Setup applied. Finish with the steps below:';
|
||
|
||
@override
|
||
String get guidedSetupBack => 'Back';
|
||
|
||
@override
|
||
String get guidedSetupNext => 'Next';
|
||
|
||
@override
|
||
String get guidedSetupCancel => 'Cancel';
|
||
|
||
@override
|
||
String get guidedSetupClose => 'Close';
|
||
|
||
@override
|
||
String get appTitle => 'Ch∆In Studio';
|
||
|
||
@override
|
||
String get navWelcome => 'Welcome';
|
||
|
||
@override
|
||
String get welcomeHeroTitle => 'Ch∆In Platform';
|
||
|
||
@override
|
||
String get welcomeHeroSubtitle =>
|
||
'Deterministic workflow engine for AI-assisted data processing in regulated environments.';
|
||
|
||
@override
|
||
String get welcomePillarHubTitle => 'Hub';
|
||
|
||
@override
|
||
String get welcomePillarHubBody =>
|
||
'The program that runs everything. It works right on your machine, needs no extra software, and keeps everything important in a single file.';
|
||
|
||
@override
|
||
String get welcomePillarHubTech =>
|
||
'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 building block that does exactly one job — reading text out of documents, say. Every module states up front what it wants to touch; the hub allows nothing more.';
|
||
|
||
@override
|
||
String get welcomePillarModuleTech =>
|
||
'A small, sandboxed WebAssembly component. 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 recipe that connects modules into fixed steps. Inputs go in, steps run in order, the result comes out — and every step is recorded tamper-evidently.';
|
||
|
||
@override
|
||
String get welcomePillarFlowTech =>
|
||
'A YAML file that chains modules together; every step is recorded in a hash-chained audit log that the Diagnostics page verifies in full.';
|
||
|
||
@override
|
||
String get welcomePillarTechToggle => 'For the technically curious';
|
||
|
||
@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 makes later edits detectable — and what integrity level WORM-1 does (and does not) provide.';
|
||
|
||
@override
|
||
String get welcomeDocFlowsTitle => 'Flow composition';
|
||
|
||
@override
|
||
String get welcomeDocFlowsBlurb =>
|
||
'YAML basics, templating reference, the extract→summarize example.';
|
||
|
||
@override
|
||
String get welcomeDocApprovalsTitle => 'Approvals';
|
||
|
||
@override
|
||
String get welcomeDocApprovalsBlurb =>
|
||
'Human-in-the-loop checkpoints — when to use them, how the audit log records them.';
|
||
|
||
@override
|
||
String get welcomeDocFederationTitle => 'Federation';
|
||
|
||
@override
|
||
String get welcomeDocFederationBlurb =>
|
||
'Connect other hubs (satellites) so their capabilities become usable here — what a satellite is and how enrolment works.';
|
||
|
||
@override
|
||
String get welcomeDocRunsTitle => 'Background runs';
|
||
|
||
@override
|
||
String get welcomeDocRunsBlurb =>
|
||
'Flows that keep working in the background — what they are for, how to switch the feature on and monitor the runs.';
|
||
|
||
@override
|
||
String get helpTooltip => 'Help';
|
||
|
||
@override
|
||
String get errApprovalRejected => 'Approval rejected by reviewer.';
|
||
|
||
@override
|
||
String get errApprovalRejectedHint =>
|
||
'The reviewer marked this step as rejected. Check the audit log for the reviewer\'s reason.';
|
||
|
||
@override
|
||
String get errApprovalTimedOut => 'Approval timed out.';
|
||
|
||
@override
|
||
String get errApprovalTimedOutHint =>
|
||
'No reviewer decided within the configured time. Raise timeout_seconds on the approval step or alert the reviewer.';
|
||
|
||
@override
|
||
String get errOutputTooLarge => 'Step output exceeded the size limit.';
|
||
|
||
@override
|
||
String get errOutputTooLargeHint =>
|
||
'Either trim the output (truncate text, downsample bytes) or raise max_output_size_mb in the operator config.';
|
||
|
||
@override
|
||
String get errServiceUnavailableForStep => 'Host service not configured.';
|
||
|
||
@override
|
||
String get errServiceUnavailableForStepHint =>
|
||
'The module requires a service (e.g. ollama, playwright) the operator hasn\'t declared. Add it under services: in ~/.chain/config.yaml.';
|
||
|
||
@override
|
||
String get errMissingValue => 'Required value is missing.';
|
||
|
||
@override
|
||
String get errMissingValueHint =>
|
||
'The step expected an input that wasn\'t wired up — either supply it at run time or fix the upstream \$ref.';
|
||
|
||
@override
|
||
String get errMcpUnreachable => 'MCP endpoint unreachable.';
|
||
|
||
@override
|
||
String get errMcpUnreachableHint =>
|
||
'The MCP server didn\'t respond. Check the endpoint in Settings → Integrations and confirm it\'s running.';
|
||
|
||
@override
|
||
String get errCapabilityNotInstalled =>
|
||
'Required capability is not installed.';
|
||
|
||
@override
|
||
String get errCapabilityNotInstalledHint =>
|
||
'Open the flow\'s Text tab — the analyzer\'s Fix button installs the capability if it\'s in the store.';
|
||
|
||
@override
|
||
String get errNoStoreEntry => 'No store entry provides this capability.';
|
||
|
||
@override
|
||
String get errNoStoreEntryHint =>
|
||
'Three ways to get it: install a local module (chain install --link <path>), add the store that provides it (Settings → Stores), or configure the integration (MCP/n8n) that supplies it. If it was just published, refresh the Store page first.';
|
||
|
||
@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. The list shows the live state — refresh top right 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 => 'Connect a public tool catalog';
|
||
|
||
@override
|
||
String get welcomeChecklistMcpHint =>
|
||
'Connects a public tool catalog (the technical term is MCP) — its capabilities then appear in the Store. Add one there, or under Settings → MCP Clients.';
|
||
|
||
@override
|
||
String get welcomeChecklistModule => 'Install a text module';
|
||
|
||
@override
|
||
String get welcomeChecklistModuleHint =>
|
||
'Install a module from the Store — pick whichever category fits your work. Modules are sandboxed Ch∆In components.';
|
||
|
||
@override
|
||
String get welcomeChecklistFlow => 'Run a saved flow';
|
||
|
||
@override
|
||
String get welcomeChecklistFlowHint =>
|
||
'Flows → pick one → Run. Studio ships a few demo flows; one of your own works too.';
|
||
|
||
@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 connectionTapToStart => 'tap to start';
|
||
|
||
@override
|
||
String get sidebarSettingsTooltip => 'Settings (⌘;)';
|
||
|
||
@override
|
||
String get sidebarChannelTooltip =>
|
||
'Active channel — click to switch.\nproduction = stable · beta = pre-release · dev = rolling · local = workspace';
|
||
|
||
@override
|
||
String get buttonCancel => 'Cancel';
|
||
|
||
@override
|
||
String get buttonLearnMore => 'Learn more';
|
||
|
||
@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 (applies instantly)';
|
||
|
||
@override
|
||
String themeApplied(String name) {
|
||
return 'Theme applied: $name';
|
||
}
|
||
|
||
@override
|
||
String get themePluginFailed =>
|
||
'Theme plugin could not load — keeping previous theme.';
|
||
|
||
@override
|
||
String get themePluginNone => 'Built-in (no plugin)';
|
||
|
||
@override
|
||
String get themePluginHint =>
|
||
'Built-in and plugin tiles ship hand-curated palettes. The Custom tile derives a full Material 3 palette (primary, secondary, tertiary, surface, …) from one seed colour you pick — it\'s a complete theme, not a single-colour tweak.';
|
||
|
||
@override
|
||
String get themePluginEmpty =>
|
||
'No theme plugins installed. Open the Store and pick one in the studio-plugin category.';
|
||
|
||
@override
|
||
String get themePluginCustom => 'Custom colour';
|
||
|
||
@override
|
||
String get themePluginCustomDialogTitle =>
|
||
'Custom theme — pick a seed colour';
|
||
|
||
@override
|
||
String get themePluginCustomHexLabel => 'Hex colour';
|
||
|
||
@override
|
||
String get themePluginCustomPreview => 'Live preview';
|
||
|
||
@override
|
||
String get themePluginCustomCancel => 'Cancel';
|
||
|
||
@override
|
||
String get themePluginCustomApply => 'Apply';
|
||
|
||
@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 => 'Connect to endpoint';
|
||
|
||
@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 ~/.chain/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 storeStatusAlphaHelp =>
|
||
'Early version: it works, but it is still evolving and not cleared for regulated production use.';
|
||
|
||
@override
|
||
String get storeStatusPublishedHelp =>
|
||
'Cleared by the publisher for general use.';
|
||
|
||
@override
|
||
String get storeStatusPlannedHelp => 'Announced, but not available yet.';
|
||
|
||
@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 get storeCategoryDocument => 'Document';
|
||
|
||
@override
|
||
String get storeCatDocuments => 'Documents';
|
||
|
||
@override
|
||
String get storeCatTextLanguage => 'Text & Language';
|
||
|
||
@override
|
||
String get storeCatData => 'Data & Formats';
|
||
|
||
@override
|
||
String get storeCatAiLlm => 'AI & LLM';
|
||
|
||
@override
|
||
String get storeCatWebApi => 'Web & APIs';
|
||
|
||
@override
|
||
String get storeCatAnalysisDomain => 'Analysis & Domain';
|
||
|
||
@override
|
||
String get storeCatStudioThemes => 'Studio & Themes';
|
||
|
||
@override
|
||
String get storeCatExamplesDev => 'Examples & Dev';
|
||
|
||
@override
|
||
String get storeCatOther => 'Other';
|
||
|
||
@override
|
||
String get storeSegmentModules => 'Modules';
|
||
|
||
@override
|
||
String get storeSegmentStudio => 'Studio & Themes';
|
||
|
||
@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 storesManagerButton => 'Add store';
|
||
|
||
@override
|
||
String get storesManagerTitle => 'Module stores';
|
||
|
||
@override
|
||
String get storesManagerIntro =>
|
||
'The hub merges the modules from every store below into one index. Add a store\'s index URL to make its modules installable here.';
|
||
|
||
@override
|
||
String get storesManagerAddSection => 'Add a store';
|
||
|
||
@override
|
||
String get storesManagerNameLabel => 'Name';
|
||
|
||
@override
|
||
String get storesManagerUrlLabel => 'Index URL (https:// or file://)';
|
||
|
||
@override
|
||
String get storesManagerAddAction => 'Add store';
|
||
|
||
@override
|
||
String storesManagerBundled(int count) {
|
||
return '$count modules · bundled';
|
||
}
|
||
|
||
@override
|
||
String storesManagerModuleCount(int count) {
|
||
return '$count modules';
|
||
}
|
||
|
||
@override
|
||
String get storesManagerAddFailed => 'Could not add store';
|
||
|
||
@override
|
||
String get storesManagerRemoveFailed => 'Could not remove store';
|
||
|
||
@override
|
||
String get storesManagerSuggested => 'Suggested stores';
|
||
|
||
@override
|
||
String get storesManagerAddShort => 'Add';
|
||
|
||
@override
|
||
String get storesManagerPinnedKeyLabel => 'Pin a signing key (PEM, optional)';
|
||
|
||
@override
|
||
String get storesManagerPinnedKeyHint =>
|
||
'Only modules signed with this key are accepted from this source. Paste the publisher\'s public key (PEM) — used instead of the built-in vendor key.';
|
||
|
||
@override
|
||
String get storesManagerNotAvailable => 'Not available yet';
|
||
|
||
@override
|
||
String get storesManagerNotAvailableHint =>
|
||
'The provider hasn\'t published this store index yet. It will become installable once they do.';
|
||
|
||
@override
|
||
String get storesSuggestedReclaimDesc =>
|
||
'Recl∆Im — modules for law & duty reform-mapping';
|
||
|
||
@override
|
||
String get storeTodayBadge => 'TODAY';
|
||
|
||
@override
|
||
String get storeFeaturedBadge => 'FEATURED';
|
||
|
||
@override
|
||
String get storeTodayDeck => 'From the Ch∆In 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 CHAIN_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 auditFilterTooltip => 'Filter events';
|
||
|
||
@override
|
||
String get auditClearLogTooltip => 'Clear log (local/dev channels only)';
|
||
|
||
@override
|
||
String get auditMoreTooltip => 'More actions';
|
||
|
||
@override
|
||
String get auditSearchHint =>
|
||
'Search events (flow, step, module, error text …)';
|
||
|
||
@override
|
||
String get auditExportAction => 'Export current view as JSONL …';
|
||
|
||
@override
|
||
String get auditExportAllAction => 'Export full log as JSONL …';
|
||
|
||
@override
|
||
String get auditExportAllNothing => 'The log is empty — nothing to export.';
|
||
|
||
@override
|
||
String get auditExportNothing =>
|
||
'No events in the current view — nothing to export.';
|
||
|
||
@override
|
||
String auditExportSaved(int n, String path) {
|
||
return 'Exported $n events to $path';
|
||
}
|
||
|
||
@override
|
||
String get auditDevResetAction =>
|
||
'Development reset: clear log … (local/dev 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 auditClearReviewerHelper =>
|
||
'Recorded as an unchecked claim (prefix \"unverified:\") — the hub stores this name as sent.';
|
||
|
||
@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 chain install <capability-name> or check ~/.chain/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 chain 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 in Studio\'s flow 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 .chain modules from a registry behind a signin wall (Forgejo, GitHub-private). Stored at ~/.chain/registry-token, mode 0600. The CHAIN_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 ~/.chain/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 authPolicyHeader => 'HUB ACCESS POLICY';
|
||
|
||
@override
|
||
String get authPolicyBlurb =>
|
||
'How the hub checks incoming calls: the active validator, the tokens and their scope grants. Secrets stay in environment variables — only their names appear here.';
|
||
|
||
@override
|
||
String get authPolicyValidatorStatic => 'Validator: static token list';
|
||
|
||
@override
|
||
String get authPolicyValidatorJwt =>
|
||
'Validator: JWT (RS256) via an external identity provider';
|
||
|
||
@override
|
||
String get authPolicyAnonymous =>
|
||
'No tokens configured — the hub accepts anonymous calls. Fine for local work; configure tokens in ~/.chain/config.yaml for production.';
|
||
|
||
@override
|
||
String get authPolicyReloadRequired =>
|
||
'The config file (or an environment variable) changed after loading — the hub still enforces the previous state. Use “Reload” below to apply the change.';
|
||
|
||
@override
|
||
String get authPolicyNeedsAdmin =>
|
||
'This view needs a token with the admin scope. Store it above under “Hub authentication” and reload.';
|
||
|
||
@override
|
||
String get authPolicyHubTooOld =>
|
||
'The connected hub does not know this view yet — it is older than Studio. Update the hub (chain update apply) and reload.';
|
||
|
||
@override
|
||
String get authPolicyRetry => 'Retry';
|
||
|
||
@override
|
||
String get authPolicyReload => 'Reload tokens';
|
||
|
||
@override
|
||
String authPolicyReloadDone(int n) {
|
||
return 'Reloaded — $n tokens active.';
|
||
}
|
||
|
||
@override
|
||
String get authPolicyEditHint =>
|
||
'The policy is edited in ~/.chain/config.yaml (auth: section). After a change or token rotation, reload here — the hub applies it without a restart.';
|
||
|
||
@override
|
||
String authPolicyEnvSet(String env) {
|
||
return 'Environment variable $env is set';
|
||
}
|
||
|
||
@override
|
||
String authPolicyEnvMissing(String env) {
|
||
return 'Environment variable $env is MISSING — the token is unusable';
|
||
}
|
||
|
||
@override
|
||
String authPolicyRateLimit(int n) {
|
||
return '$n/min';
|
||
}
|
||
|
||
@override
|
||
String get authPolicyJwtKeySource => 'Key source';
|
||
|
||
@override
|
||
String get authPolicyJwtAudience => 'Audience (aud)';
|
||
|
||
@override
|
||
String get authPolicyJwtIssuer => 'Issuer (iss)';
|
||
|
||
@override
|
||
String get authPolicyJwtScopeClaim => 'Scope claim';
|
||
|
||
@override
|
||
String get authPolicyNotChecked => 'not checked';
|
||
|
||
@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 ~/.chain/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 ~/.chain/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 uninstallVersionPickerTitle => 'Pick a version to uninstall';
|
||
|
||
@override
|
||
String uninstallVersionPickerBody(String module) {
|
||
return 'Several versions of $module are installed side-by-side. Select the exact version to remove — the others stay in place.';
|
||
}
|
||
|
||
@override
|
||
String get uninstallVersionPickerContinue => 'Continue';
|
||
|
||
@override
|
||
String get defaultScopeHeader => 'DEFAULT SCOPE';
|
||
|
||
@override
|
||
String get defaultScopeBlurb =>
|
||
'Ordered list of publisher segments the hub consults when a flow names a capability without an explicit <provider>/ prefix. First match wins — promote the segments your team uses most to the top. Catalog-known publishers appear as chips; arbitrary entries are accepted for private segments.';
|
||
|
||
@override
|
||
String get defaultScopeAddLabel => 'Add publisher segment';
|
||
|
||
@override
|
||
String get defaultScopeAddHint => 'e.g. acme.team';
|
||
|
||
@override
|
||
String get defaultScopeAddButton => 'Add';
|
||
|
||
@override
|
||
String get defaultScopeSuggestions => 'Catalog suggestions:';
|
||
|
||
@override
|
||
String get defaultScopeSavedToast => 'Default scope updated.';
|
||
|
||
@override
|
||
String get defaultScopeLoadFailed => 'Could not load default scope.';
|
||
|
||
@override
|
||
String get defaultScopeNonEmptyError =>
|
||
'Default scope cannot be empty — keep at least one segment.';
|
||
|
||
@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 ~/.chain/ 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 ~/.chain/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 ~/.chain/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 ~/.chain/ 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 chain 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 ~/.chain/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 ~/.chain/logs/. If this repeats, please report it.';
|
||
|
||
@override
|
||
String get errUnavailable => 'Hub not reachable.';
|
||
|
||
@override
|
||
String get errUnavailableHint =>
|
||
'Make sure chain serve (or chain daemon start) is running and the daemon endpoint matches Studio\'s settings.';
|
||
|
||
@override
|
||
String get errUnauthenticated => 'Authentication required.';
|
||
|
||
@override
|
||
String get errUnauthenticatedHint =>
|
||
'Set CHAIN_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. When a flow asks for a human approval, the request appears 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 => 'DATA TO REVIEW';
|
||
|
||
@override
|
||
String get approvalsNoPayload =>
|
||
'No data was attached to this approval. You are deciding without a detail view — when in doubt, ask whoever set up the process. (Technical: the approval step\'s \"show:\" field controls what appears here.)';
|
||
|
||
@override
|
||
String get approvalsNoDataConfirmTitle => 'Approve without review data?';
|
||
|
||
@override
|
||
String get approvalsNoDataConfirmBody =>
|
||
'This flow deliberately attached no review data (no \"show:\" on its approval step). You can still approve — but you would be deciding without seeing the data behind this decision.';
|
||
|
||
@override
|
||
String get approvalsNoDataConfirmAction => 'Approve anyway';
|
||
|
||
@override
|
||
String get approvalsRequestFallback => 'Approval required for this step';
|
||
|
||
@override
|
||
String approvalsFlowStepMeta(String flow, String step) {
|
||
return 'Flow: $flow · Step: $step';
|
||
}
|
||
|
||
@override
|
||
String get approvalsIntroHelp =>
|
||
'Paused processes (flows) waiting for your decision. Each card shows which process is holding at which step and what data it puts in front of you — Approve resumes it, Reject stops it with your reason.';
|
||
|
||
@override
|
||
String get approvalsReviewerLabel => 'You are deciding as';
|
||
|
||
@override
|
||
String get approvalsReviewerUnverifiedPill => 'not verified';
|
||
|
||
@override
|
||
String approvalsReviewerRecordedAs(Object value) {
|
||
return 'Recorded as: $value';
|
||
}
|
||
|
||
@override
|
||
String get approvalsReviewerNoteAnonymous =>
|
||
'This hub accepts calls without credentials, so a decision cannot be proven to be anyone\'s. Studio therefore marks the name inside the record itself as an unchecked claim.';
|
||
|
||
@override
|
||
String get approvalsReviewerNoteAuthenticated =>
|
||
'The hub checks your access but records the name exactly as Studio sends it. Until the hub derives the identity from the checked access itself, Studio marks the name inside the record as an unchecked claim.';
|
||
|
||
@override
|
||
String get approvalsReviewerNoteUnknown =>
|
||
'Studio could not read this hub\'s access settings (that needs admin rights). The name is stored exactly as sent and is therefore marked inside the record as an unchecked claim.';
|
||
|
||
@override
|
||
String get approvalsReviewerUnverifiedTooltip =>
|
||
'Unchecked claim: this name comes from the deciding Studio, not from the hub.';
|
||
|
||
@override
|
||
String get approvalsRejectDialogHelp =>
|
||
'Rejecting stops the process at this step and is recorded with your reason in the audit trail.';
|
||
|
||
@override
|
||
String get approvalsRejectReasonHelper =>
|
||
'Required — recorded in the audit log.';
|
||
|
||
@override
|
||
String get approvalsBatchNoDataTitle => 'Approve without review data?';
|
||
|
||
@override
|
||
String approvalsBatchNoDataBody(num count, Object total) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
count,
|
||
locale: localeName,
|
||
other:
|
||
'$count of $total selected approvals have no review data. You are approving them without a detail view.',
|
||
one:
|
||
'1 of $total selected approvals has no review data. You are approving it without a detail view.',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get approvalsCopyRun => 'Copy run id';
|
||
|
||
@override
|
||
String get approvalsRunCopied => 'Run id copied';
|
||
|
||
@override
|
||
String get approvalsUnknownReviewer => '(unknown)';
|
||
|
||
@override
|
||
String get approvalsOriginLabel => 'ORIGIN';
|
||
|
||
@override
|
||
String get approvalsOriginProject => 'Project';
|
||
|
||
@override
|
||
String get approvalsOriginRequested => 'Requested';
|
||
|
||
@override
|
||
String get approvalsOriginRun => 'Run';
|
||
|
||
@override
|
||
String get approvalsApproveTooltip => 'Resumes the flow at this step';
|
||
|
||
@override
|
||
String get approvalsRejectTooltip => 'Stops the flow — with your reason';
|
||
|
||
@override
|
||
String get approvalsApproveButton => 'Approve';
|
||
|
||
@override
|
||
String get approvalsRejectButton => 'Reject';
|
||
|
||
@override
|
||
String get approvalsRejectDialogTitle => 'Reject approval';
|
||
|
||
@override
|
||
String get approvalsRejectReasonLabel => 'Reason';
|
||
|
||
@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 => 'QUESTION';
|
||
|
||
@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) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: '$n capabilities',
|
||
one: '1 capability',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryPending => 'pending';
|
||
|
||
@override
|
||
String doctorSummaryChain(int verified, int total) {
|
||
return '$verified of $total events verified';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryDeclared => 'declared';
|
||
|
||
@override
|
||
String doctorOllamaSuggest(String endpoint) {
|
||
return 'The system AI uses Ollama at $endpoint — declare it as a host service so modules and the doctor know it?';
|
||
}
|
||
|
||
@override
|
||
String get doctorOllamaDeclareButton => 'Declare as host service';
|
||
|
||
@override
|
||
String get doctorOllamaDeclared =>
|
||
'Declared as host service \"ollama\" — takes effect after a daemon restart (button further down this page).';
|
||
|
||
@override
|
||
String updateHintBanner(String local, String latest) {
|
||
return 'Version $latest is available for the hub ($local).';
|
||
}
|
||
|
||
@override
|
||
String get updateHintOpenDoctor => 'Open Doctor';
|
||
|
||
@override
|
||
String get updateHintDismiss => 'Later';
|
||
|
||
@override
|
||
String get svcExposureLoopback => 'local only';
|
||
|
||
@override
|
||
String get svcExposurePrivate => 'private network';
|
||
|
||
@override
|
||
String get svcExposurePublic => 'publicly reachable';
|
||
|
||
@override
|
||
String get svcExposureUnknown => 'reach unknown';
|
||
|
||
@override
|
||
String get svcExposurePublicHint =>
|
||
'This service endpoint sits on a public address — make sure it is protected (TLS, auth, firewall).';
|
||
|
||
@override
|
||
String get svcExposureUnknownHint =>
|
||
'Hostname instead of an IP address — the hub deliberately does not resolve names to classify. Check yourself where the name resolves.';
|
||
|
||
@override
|
||
String get doctorLinkStore => 'Open the store';
|
||
|
||
@override
|
||
String get doctorLinkApprovals => 'Open approvals';
|
||
|
||
@override
|
||
String get doctorLinkAudit => 'Open the audit log';
|
||
|
||
@override
|
||
String get doctorLinkConfig => 'View the configuration';
|
||
|
||
@override
|
||
String get doctorLinkReleaseNotes => 'Open the release notes in the browser';
|
||
|
||
@override
|
||
String doctorModulesPanelSummary(int n, int m) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: '$n modules',
|
||
one: '1 module',
|
||
);
|
||
String _temp1 = intl.Intl.pluralLogic(
|
||
m,
|
||
locale: localeName,
|
||
other: '$m capabilities',
|
||
one: '1 capability',
|
||
);
|
||
return '$_temp0 · $_temp1';
|
||
}
|
||
|
||
@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 ~/.chain/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) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'events',
|
||
one: 'event',
|
||
);
|
||
return '$n $_temp0 · linkage 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 => 'Hash chain verified';
|
||
|
||
@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 chain daemon … exactly so the CLI and UI stay in lockstep.';
|
||
|
||
@override
|
||
String get doctorDaemonControlWorking => 'Working…';
|
||
|
||
@override
|
||
String doctorConnLine(String endpoint, String transport, String auth) {
|
||
return 'Connection: $endpoint · $transport · $auth';
|
||
}
|
||
|
||
@override
|
||
String get doctorConnTls => 'TLS-encrypted';
|
||
|
||
@override
|
||
String get doctorConnPlainLocal => 'unencrypted (stays on this machine)';
|
||
|
||
@override
|
||
String get doctorConnPlainRemote => 'unencrypted';
|
||
|
||
@override
|
||
String doctorConnToken(int count) {
|
||
return 'token configured ($count characters)';
|
||
}
|
||
|
||
@override
|
||
String get doctorConnAnonymous => 'no token (anonymous)';
|
||
|
||
@override
|
||
String get doctorDbVolatileWarning =>
|
||
'The audit database is stored in a temporary folder the operating system may clean up at any time. For real evidence, move the hub\'s data directory to a permanent location.';
|
||
|
||
@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 chain 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 chain 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 hubViewTooOldTitle => 'This view needs a newer hub version';
|
||
|
||
@override
|
||
String get hubViewTooOldHint =>
|
||
'The hub is connected, but its version does not know this view yet. Update the hub (Doctor → Update) and the content will appear here.';
|
||
|
||
@override
|
||
String get hubViewLoadFailedTitle => 'This view could not be loaded';
|
||
|
||
@override
|
||
String get hubUnreachableHint => 'Start the hub with chain 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 searchGroupWorkspace => 'Projects & areas';
|
||
|
||
@override
|
||
String get searchWorkspaceHint => 'switch context · ⌘P';
|
||
|
||
@override
|
||
String get searchWorkspaceSealedPickerHint => 'open the picker · ⌘P';
|
||
|
||
@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';
|
||
|
||
@override
|
||
String get navFlowEditor => 'Editor';
|
||
|
||
@override
|
||
String get flowEditorBackTooltip => 'Back';
|
||
|
||
@override
|
||
String get flowEditorNew => 'New flow';
|
||
|
||
@override
|
||
String get flowEditorSave => 'Save';
|
||
|
||
@override
|
||
String get flowEditorRun => 'Run';
|
||
|
||
@override
|
||
String get flowEditorRefresh => 'Refresh file list';
|
||
|
||
@override
|
||
String get flowEditorRunOutput => 'RUN OUTPUT';
|
||
|
||
@override
|
||
String get flowEditorEmptyTitle => 'No flow open';
|
||
|
||
@override
|
||
String get flowEditorEmptyBody =>
|
||
'Pick one from the left, or click New flow to start a fresh one.';
|
||
|
||
@override
|
||
String get flowEditorListEmptyTitle => 'No saved flows';
|
||
|
||
@override
|
||
String get flowEditorListEmptyBody =>
|
||
'Click New flow to scaffold one from a template.';
|
||
|
||
@override
|
||
String get flowEditorDiscardTitle => 'Discard unsaved changes?';
|
||
|
||
@override
|
||
String get flowEditorDiscardBody =>
|
||
'Switching files will throw away the edits you haven\'t saved.';
|
||
|
||
@override
|
||
String get flowEditorDiscardKeep => 'Keep editing';
|
||
|
||
@override
|
||
String get flowEditorDiscardThrow => 'Throw away';
|
||
|
||
@override
|
||
String get flowEditorNewDialogTitle => 'New flow';
|
||
|
||
@override
|
||
String get flowEditorNewDialogLabel => 'Flow name';
|
||
|
||
@override
|
||
String get flowEditorNewDialogHelper =>
|
||
'lowercase letters, digits, hyphen, underscore';
|
||
|
||
@override
|
||
String get flowEditorNewDialogCancel => 'Cancel';
|
||
|
||
@override
|
||
String get flowEditorNewDialogCreate => 'Create';
|
||
|
||
@override
|
||
String flowEditorNewTemplateComment(String name) {
|
||
return 'Generated by Studio\'s Flow editor. Edit, save, run.';
|
||
}
|
||
|
||
@override
|
||
String flowEditorAlreadyExists(String name) {
|
||
return 'A flow named \"$name\" already exists.';
|
||
}
|
||
|
||
@override
|
||
String get buttonView => 'View';
|
||
|
||
@override
|
||
String logViewerTitle(String title, int count) {
|
||
return '$title — last $count lines';
|
||
}
|
||
|
||
@override
|
||
String get logViewerEmpty => 'Log file is empty or does not exist yet.';
|
||
|
||
@override
|
||
String get logViewerCopyAll => 'Copy all';
|
||
|
||
@override
|
||
String get logViewerOpenExternal => 'Open in default editor';
|
||
|
||
@override
|
||
String logViewerLineCount(int count) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
count,
|
||
locale: localeName,
|
||
other: '$count lines',
|
||
one: '1 line',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get doctorPathStudioErrors => 'Studio errors';
|
||
|
||
@override
|
||
String get settingsCategoryGeneral => 'General';
|
||
|
||
@override
|
||
String get settingsCategoryAppearance => 'Appearance';
|
||
|
||
@override
|
||
String get settingsCategoryAbout => 'About';
|
||
|
||
@override
|
||
String get aboutPanelTitle => 'About Ch∆In';
|
||
|
||
@override
|
||
String get aboutPanelBody =>
|
||
'Product, vendor, and license details of this installation — every value is copyable.';
|
||
|
||
@override
|
||
String get aboutProduct => 'Product';
|
||
|
||
@override
|
||
String get aboutStudioVersion => 'Studio version';
|
||
|
||
@override
|
||
String get aboutHubVersion => 'Hub version';
|
||
|
||
@override
|
||
String get aboutHubVersionUnknown => 'not connected';
|
||
|
||
@override
|
||
String get aboutVendor => 'Vendor';
|
||
|
||
@override
|
||
String get aboutAuthor => 'Author';
|
||
|
||
@override
|
||
String get aboutLicense => 'License';
|
||
|
||
@override
|
||
String get aboutContact => 'Contact';
|
||
|
||
@override
|
||
String get aboutDocs => 'Documentation';
|
||
|
||
@override
|
||
String get aboutOpenLink => 'Open in browser';
|
||
|
||
@override
|
||
String get aboutCopyTooltip => 'Copy';
|
||
|
||
@override
|
||
String get aboutCopiedToast => 'Copied to the clipboard.';
|
||
|
||
@override
|
||
String get sidebarSearchLabel => 'Search & commands';
|
||
|
||
@override
|
||
String installConfirmTitle(String name) {
|
||
return 'Install \"$name\"?';
|
||
}
|
||
|
||
@override
|
||
String get installConfirmVersion => 'Version';
|
||
|
||
@override
|
||
String get installConfirmSource => 'Source';
|
||
|
||
@override
|
||
String get installConfirmSourceBundled => 'Bundled store index';
|
||
|
||
@override
|
||
String get installConfirmLicense => 'License';
|
||
|
||
@override
|
||
String get installConfirmStatus => 'Maturity';
|
||
|
||
@override
|
||
String get installConfirmNeedsServices => 'Required services';
|
||
|
||
@override
|
||
String get installConfirmNeedsCapabilities => 'Required capabilities';
|
||
|
||
@override
|
||
String get installConfirmTrustTitle => 'Trust & security';
|
||
|
||
@override
|
||
String get installConfirmTrustBody =>
|
||
'The module runs in a sandbox: it may only touch the network endpoints, files, and environment variables it declares itself — the hub enforces that list. The full permission list is visible in the module details after installation.';
|
||
|
||
@override
|
||
String get storeSectionMaintainers => 'Maintainers';
|
||
|
||
@override
|
||
String get storeMaintainersNone => 'not specified';
|
||
|
||
@override
|
||
String get installConfirmMaintainers => 'Maintainers';
|
||
|
||
@override
|
||
String get storePolicyUnverifiedNotice =>
|
||
'Signature enforcement is switched off in the hub policy — installs are not cryptographically verified. The install dialog shows the per-module status; enable security.require_signatures for verified installs.';
|
||
|
||
@override
|
||
String get verifPillBlocked => 'blocked';
|
||
|
||
@override
|
||
String get verifPinnedKey => 'Signature checked — pinned store key';
|
||
|
||
@override
|
||
String get verifPinnedKeyBody =>
|
||
'The hub verifies the bundle at install time against this source\'s pinned key. A tampered bundle is refused.';
|
||
|
||
@override
|
||
String get verifTrustedPublishers => 'Signature checked — trusted publishers';
|
||
|
||
@override
|
||
String get verifTrustedPublishersBody =>
|
||
'The hub verifies the signature at install time against the trusted-publisher list. A bundle without a valid signature is refused.';
|
||
|
||
@override
|
||
String get verifUnverified => 'Installs without signature checking';
|
||
|
||
@override
|
||
String get verifUnverifiedBody =>
|
||
'Signature enforcement is switched off in the hub policy — this bundle is not cryptographically verified at install time. Enable security.require_signatures for verified installs.';
|
||
|
||
@override
|
||
String get verifBlocked => 'An install would be refused';
|
||
|
||
@override
|
||
String get verifBlockedBody =>
|
||
'The policy requires signatures, but no key material applies to this source — the hub would refuse the install.';
|
||
|
||
@override
|
||
String get verifFederated =>
|
||
'Connected via an integration — no bundle signature';
|
||
|
||
@override
|
||
String get verifFederatedBody =>
|
||
'This entry is not an installable bundle; it runs through a configured integration (e.g. MCP or n8n). There is no bundle signature — trust follows the integration.';
|
||
|
||
@override
|
||
String get installConfirmSignatureNote =>
|
||
'The hub verifies signatures at install time whenever the security profile requires them. The store index does not yet show a per-entry signature status up front (alpha).';
|
||
|
||
@override
|
||
String get settingsSidebarPinnedTitle => 'Keep the navigation expanded';
|
||
|
||
@override
|
||
String get settingsSidebarPinnedBody =>
|
||
'Shows the sidebar labels permanently instead of only while hovering with the mouse.';
|
||
|
||
@override
|
||
String get settingsCategoryAi => 'System AI';
|
||
|
||
@override
|
||
String get settingsCategoryIntegrations => 'Integrations';
|
||
|
||
@override
|
||
String get settingsCategorySecurity => 'Security';
|
||
|
||
@override
|
||
String get settingsCategoryMaintenance => 'Maintenance';
|
||
|
||
@override
|
||
String get settingsAiPanelTitle => 'System AI';
|
||
|
||
@override
|
||
String get settingsAiPanelBody =>
|
||
'Operator-managed LLM endpoint used by Studio for the AI helpers (system-ai-edit, install-suggest, doctor-summary). No flow ever calls this; modules speak to their own LLM.';
|
||
|
||
@override
|
||
String get settingsIntegrationsPanelTitle => 'Integrations';
|
||
|
||
@override
|
||
String get settingsIntegrationsPanelBody =>
|
||
'External tool servers the hub federates capabilities from. MCP servers expose tool-shaped endpoints; n8n endpoints expose hosted workflows.';
|
||
|
||
@override
|
||
String get settingsSecurityPanelTitle => 'Security & credentials';
|
||
|
||
@override
|
||
String get settingsSecurityPanelBody =>
|
||
'Tokens the hub holds on the operator\'s behalf. Stored in ~/.chain/ with mode 0600; never sent in telemetry.';
|
||
|
||
@override
|
||
String get settingsMaintenancePanelTitle => 'Maintenance';
|
||
|
||
@override
|
||
String get settingsMaintenancePanelBody =>
|
||
'Destructive operations gated behind explicit confirm dialogs. Use when re-pilot-testing or debugging.';
|
||
|
||
@override
|
||
String get tooltipMoveUp => 'Move up';
|
||
|
||
@override
|
||
String get tooltipMoveDown => 'Move down';
|
||
|
||
@override
|
||
String get tooltipRemove => 'Remove';
|
||
|
||
@override
|
||
String get daemonActionEnableAutostart => 'enable autostart';
|
||
|
||
@override
|
||
String get daemonActionDisableAutostart => 'disable autostart';
|
||
|
||
@override
|
||
String get daemonActionRestart => 'daemon restart';
|
||
|
||
@override
|
||
String get daemonActionStart => 'daemon start';
|
||
|
||
@override
|
||
String get daemonActionStop => 'daemon stop';
|
||
|
||
@override
|
||
String get daemonActionStatus => 'daemon status';
|
||
|
||
@override
|
||
String daemonActionResultOk(String label) {
|
||
return 'OK · $label';
|
||
}
|
||
|
||
@override
|
||
String daemonActionResultFailed(String label) {
|
||
return 'Failed · $label';
|
||
}
|
||
|
||
@override
|
||
String get addSourceTitle => 'Add module source';
|
||
|
||
@override
|
||
String addSourceIntro(String capability) {
|
||
return '$capability is not in the public store. Point the hub at a .chain bundle URL or a local bundle path; the hub downloads, verifies (sha256 + signature) and installs it.';
|
||
}
|
||
|
||
@override
|
||
String get addSourceField => 'URL or path to .chain bundle';
|
||
|
||
@override
|
||
String get addSourceHint =>
|
||
'https://git.flemming.ai/your-org/your-module/releases/download/v0.1.0/foo-0.1.0.chain';
|
||
|
||
@override
|
||
String get addSourceHowItWorksTitle => 'How private modules work';
|
||
|
||
@override
|
||
String get addSourceHowItWorksBody =>
|
||
'A module is a directory with a module.yaml + the WASM artifact. To share it: pack it (chain pack <dir>) and host the resulting .chain bundle anywhere (your own Forgejo / GitHub / S3). The hub installs by URL and verifies the signature against its trust store.\n\nDeveloping locally? Use the CLI — Studio cannot install from an unpacked directory (yet):';
|
||
|
||
@override
|
||
String get addSourceCliExample => 'chain install --link /path/to/module';
|
||
|
||
@override
|
||
String get addSourceInstallButton => 'Install';
|
||
|
||
@override
|
||
String get addSourceCancel => 'Cancel';
|
||
|
||
@override
|
||
String installFailed(String error) {
|
||
return 'Install failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get welcomeHubDownTitle => 'The hub isn\'t running yet';
|
||
|
||
@override
|
||
String get welcomeHubDownBody =>
|
||
'Studio talks to a local hub — the engine that loads modules and runs flows. It isn\'t reachable right now. Start it to begin.';
|
||
|
||
@override
|
||
String get welcomeHubDownStart => 'Start hub';
|
||
|
||
@override
|
||
String get welcomeHubDownStarting => 'Starting…';
|
||
|
||
@override
|
||
String get welcomeHubDownDocsLink =>
|
||
'Can\'t start it? Read the getting-started guide';
|
||
|
||
@override
|
||
String welcomeHubDownEndpoint(String endpoint) {
|
||
return 'Endpoint: $endpoint';
|
||
}
|
||
|
||
@override
|
||
String get daemonStartRequested => 'Daemon start requested. Reconnecting…';
|
||
|
||
@override
|
||
String daemonStartFailed(String detail) {
|
||
return 'Could not start daemon: $detail';
|
||
}
|
||
|
||
@override
|
||
String get chainBinaryNotFound =>
|
||
'Could not find the chain program on this machine.';
|
||
|
||
@override
|
||
String get chainBinaryNotFoundHint =>
|
||
'Install the Ch∆In platform, or point Studio at an existing chain binary.';
|
||
|
||
@override
|
||
String get chainBinaryLocateButton => 'Locate chain binary…';
|
||
|
||
@override
|
||
String get chainBinaryInstallDocsButton => 'Open install guide';
|
||
|
||
@override
|
||
String get chainBinaryPickerTitle => 'Select the chain binary';
|
||
|
||
@override
|
||
String chainBinarySetOk(String path) {
|
||
return 'Using chain binary at $path';
|
||
}
|
||
|
||
@override
|
||
String get sysAiFixParse =>
|
||
'The provider sent a response in an unexpected format. Providers that aren\'t OpenAI-compatible may need a translation proxy.';
|
||
|
||
@override
|
||
String sysAiFixUnknown(String kind) {
|
||
return 'Unexpected failure ($kind). See the System AI documentation.';
|
||
}
|
||
|
||
@override
|
||
String get sysAiFixDisabled =>
|
||
'Configure System AI in Settings (Cmd+,) → System AI panel.';
|
||
|
||
@override
|
||
String get sysAiFixEnvMissing =>
|
||
'The API-key environment variable is empty. Set it in your shell, then restart the daemon.';
|
||
|
||
@override
|
||
String get sysAiFixNetwork =>
|
||
'The hub can\'t reach the configured endpoint. Is your provider running?';
|
||
|
||
@override
|
||
String get sysAiFixHttp =>
|
||
'The provider returned a non-2xx status. Verify the endpoint, model name, and API key.';
|
||
|
||
@override
|
||
String get sysAiFixEmptyResponse =>
|
||
'The provider answered with no content. Try a different model or rephrase the prompt.';
|
||
|
||
@override
|
||
String channelSwitchOk(String name) {
|
||
return 'Switched active channel to \"$name\". Daemon restarted.';
|
||
}
|
||
|
||
@override
|
||
String channelSwitchFailed(String detail) {
|
||
return 'Channel switch failed: $detail';
|
||
}
|
||
|
||
@override
|
||
String get providerDescOllama =>
|
||
'Local ollama serve. Models stay on your machine. No API key needed.';
|
||
|
||
@override
|
||
String get providerDescOpenai =>
|
||
'OpenAI hosted API. Requires an API key. Data leaves your machine.';
|
||
|
||
@override
|
||
String get providerDescLmstudio =>
|
||
'Local LM Studio server. Models stay on your machine. No API key needed.';
|
||
|
||
@override
|
||
String get providerDescVllm =>
|
||
'Self-hosted vLLM or any other OpenAI-compatible server. Endpoint required.';
|
||
|
||
@override
|
||
String get providerDescCustom =>
|
||
'Anything else that speaks the OpenAI-compatible chat-completions wire (LiteLLM proxy, internal mirror, …).';
|
||
|
||
@override
|
||
String welcomeDocLoadFailedBody(
|
||
String slug,
|
||
String locale,
|
||
String attempted,
|
||
String underlying,
|
||
) {
|
||
return 'Could not load the bundled doc \"$slug\" ($locale).\nTried: $attempted\nUnderlying: $underlying\nThis usually means the Studio build on disk predates the doc bundle. Rebuild Studio or open the online copy.';
|
||
}
|
||
|
||
@override
|
||
String hubUnreachableBanner(String endpoint) {
|
||
return 'Can\'t reach $endpoint — open Settings';
|
||
}
|
||
|
||
@override
|
||
String get hubUnreachableOpenSettings => 'Open Settings';
|
||
|
||
@override
|
||
String hubAuthRejectedBanner(String endpoint) {
|
||
return '$endpoint rejected the sign-in — check the access token';
|
||
}
|
||
|
||
@override
|
||
String get navFederation => 'Federation';
|
||
|
||
@override
|
||
String get federationTitle => 'Federation';
|
||
|
||
@override
|
||
String get federationReloadTooltip => 'Reload satellites';
|
||
|
||
@override
|
||
String get federationAddSatellite => 'Add satellite';
|
||
|
||
@override
|
||
String get federationEmptyTitle => 'No satellites connected';
|
||
|
||
@override
|
||
String get federationEmptyHint =>
|
||
'Connect another hub as a satellite to run capabilities on it. Issue an enrollment token to get started.';
|
||
|
||
@override
|
||
String get federationPillConnected => 'connected';
|
||
|
||
@override
|
||
String get federationRegionNone => 'no region';
|
||
|
||
@override
|
||
String federationCapabilities(int count) {
|
||
return '$count advertised capabilities';
|
||
}
|
||
|
||
@override
|
||
String get federationAddDialogTitle => 'Issue an enrollment token';
|
||
|
||
@override
|
||
String get federationNameLabel => 'Satellite name';
|
||
|
||
@override
|
||
String get federationAddIntro =>
|
||
'A satellite is another hub this hub connects to — its capabilities then become usable here in flows. You give it a name and receive a one-time token the satellite uses to enrol with this hub.';
|
||
|
||
@override
|
||
String get federationNameHelp =>
|
||
'A free-form name to recognize this satellite in the list (e.g. its location or purpose). Display only — it changes nothing technical.';
|
||
|
||
@override
|
||
String get federationIssueButton => 'Issue';
|
||
|
||
@override
|
||
String federationIssueFailed(String error) {
|
||
return 'Could not issue token: $error';
|
||
}
|
||
|
||
@override
|
||
String federationEnrollmentTitle(String name) {
|
||
return 'Enroll $name';
|
||
}
|
||
|
||
@override
|
||
String get federationTokenLabel => 'Bootstrap token (single use)';
|
||
|
||
@override
|
||
String get federationConfigLabel =>
|
||
'Satellite config (paste into the satellite)';
|
||
|
||
@override
|
||
String get federationCopied => 'Copied to clipboard';
|
||
|
||
@override
|
||
String get federationEnrollmentHint =>
|
||
'Hand the token to the satellite operator over a secure channel. The bundled CA authenticates the satellite\'s first connect.';
|
||
|
||
@override
|
||
String get workspaceAll => 'All projects';
|
||
|
||
@override
|
||
String get workspaceDefaultProject => 'General';
|
||
|
||
@override
|
||
String get workspaceSwitcherTooltip =>
|
||
'Choose the working context — applies everywhere: filters flows, runs, audit and approvals, and stamps new runs with the selected project';
|
||
|
||
@override
|
||
String get workspaceAnchorCaption => 'Project / area';
|
||
|
||
@override
|
||
String workspaceStartConfirmTitle(String name) {
|
||
return 'Start area “$name”?';
|
||
}
|
||
|
||
@override
|
||
String get workspaceStartConfirmBody =>
|
||
'This sealed area is currently stopped. Studio starts its own hub instance on this machine and connects to it — running areas switch without this prompt.';
|
||
|
||
@override
|
||
String get workspaceStartConfirmAction => 'Start and connect';
|
||
|
||
@override
|
||
String get workspaceSealedAggregateWhy =>
|
||
'Names stay aggregated because they can reveal client identities.';
|
||
|
||
@override
|
||
String get workspaceSealedAggregateSettings =>
|
||
'Always show: Settings → Security';
|
||
|
||
@override
|
||
String get workspaceProtectedHint =>
|
||
'Protected: logically separated in the shared hub — no hard process barrier. Critical engagements use a sealed area.';
|
||
|
||
@override
|
||
String get runsTitle => 'Runs';
|
||
|
||
@override
|
||
String get runsReloadTooltip => 'Reload the runs list';
|
||
|
||
@override
|
||
String get runsEmptyTitle => 'No background runs';
|
||
|
||
@override
|
||
String get runsEmptyHint =>
|
||
'Runs that keep working in the background while you do something else appear here. The feature is optional and off by default — the guide shows step by step how to turn it on.';
|
||
|
||
@override
|
||
String get runsEmptyEnabledHint =>
|
||
'Background runs are switched on — none has been started yet. Start a flow with the \"run in background\" option and it will appear here.';
|
||
|
||
@override
|
||
String get runsEmptyGuideButton => 'Open the guide';
|
||
|
||
@override
|
||
String runsEmptyFilteredTitle(String name) {
|
||
return 'No runs in project “$name”';
|
||
}
|
||
|
||
@override
|
||
String get runsEmptyFilteredHint =>
|
||
'The working context filters this list — other projects may have runs.';
|
||
|
||
@override
|
||
String get runsEmptyShowAll => 'Show all projects';
|
||
|
||
@override
|
||
String get runsHubTooOldTitle => 'This view needs a newer hub version';
|
||
|
||
@override
|
||
String get runsHubTooOldHint =>
|
||
'The hub is connected, but its version does not know the runs monitor yet. Update the hub and the runs will appear here.';
|
||
|
||
@override
|
||
String get runsHubTooOldButton => 'Open Doctor';
|
||
|
||
@override
|
||
String get runsHubUpdateButton => 'Update hub now';
|
||
|
||
@override
|
||
String get runsHubUpdateStarted => 'Updating hub…';
|
||
|
||
@override
|
||
String get runsLoadFailedTitle => 'Runs could not be loaded';
|
||
|
||
@override
|
||
String get runsCancelButton => 'Cancel';
|
||
|
||
@override
|
||
String runsCancelSignalled(String flow) {
|
||
return 'Cancel signalled for $flow.';
|
||
}
|
||
|
||
@override
|
||
String get runsCancelTooLate =>
|
||
'The run had already finished — nothing to cancel.';
|
||
|
||
@override
|
||
String runsCurrentStep(String step) {
|
||
return 'Step: $step';
|
||
}
|
||
|
||
@override
|
||
String get runsPhasePending => 'Pending';
|
||
|
||
@override
|
||
String get runsPhaseRunning => 'Running';
|
||
|
||
@override
|
||
String get runsPhaseSucceeded => 'Succeeded';
|
||
|
||
@override
|
||
String get runsPhaseFailed => 'Failed';
|
||
|
||
@override
|
||
String get runsPhaseCancelled => 'Cancelled';
|
||
|
||
@override
|
||
String get runsPhaseUnknown => 'Unknown';
|
||
|
||
@override
|
||
String get navRuns => 'Runs';
|
||
|
||
@override
|
||
String get workspaceSealedHeader => 'SEALED AREAS';
|
||
|
||
@override
|
||
String workspaceSealedAggregate(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: '$n sealed areas',
|
||
one: '1 sealed area',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get workspaceSealedRevealAction => 'Show names';
|
||
|
||
@override
|
||
String get settingsSealedNamesTitle =>
|
||
'List sealed areas with their names right away';
|
||
|
||
@override
|
||
String get settingsSealedNamesBody =>
|
||
'Area names can be sensitive (client/mandate identity). By default the workspace switcher shows them aggregated; the names appear only after a click.';
|
||
|
||
@override
|
||
String get workspaceSealedRunning => 'running';
|
||
|
||
@override
|
||
String get workspaceSealedStopped => 'stopped';
|
||
|
||
@override
|
||
String get workspaceSealedRunningHint =>
|
||
'The sealed area runs as its own hub process. Selecting it switches in.';
|
||
|
||
@override
|
||
String get workspaceSealedStoppedHint =>
|
||
'The sealed area is not running right now. Selecting it starts it and switches in.';
|
||
|
||
@override
|
||
String workspaceSealedStarting(String name) {
|
||
return 'Starting sealed area “$name”…';
|
||
}
|
||
|
||
@override
|
||
String workspaceSealedStarted(String name) {
|
||
return 'Started sealed area “$name”.';
|
||
}
|
||
|
||
@override
|
||
String workspaceSealedSwitchFailed(String error) {
|
||
return 'Could not switch to the sealed area: $error';
|
||
}
|
||
|
||
@override
|
||
String get sealedIdentityBar =>
|
||
'Sealed area — isolated hub, own data and audit chain';
|
||
|
||
@override
|
||
String get sealedSwitchingBar =>
|
||
'Switching connection — data appears once the switch completes';
|
||
|
||
@override
|
||
String get sealedLeave => 'Leave';
|
||
|
||
@override
|
||
String setupStepOf(int n, int total) {
|
||
return 'Step $n of $total';
|
||
}
|
||
|
||
@override
|
||
String get setupStep1Title => 'What are the stakes?';
|
||
|
||
@override
|
||
String get setupStep2Title => 'What do you want to do first?';
|
||
|
||
@override
|
||
String get setupStep3Title => 'Where will it run?';
|
||
|
||
@override
|
||
String get setupReviewTitle => 'This is what Ch∆In will set up';
|
||
|
||
@override
|
||
String get setupChooseFreeText => 'Or just describe what you want to do';
|
||
|
||
@override
|
||
String get setupScenTryingOut => 'Just trying it out';
|
||
|
||
@override
|
||
String get setupScenTryingOutSub =>
|
||
'A straightforward workstation on this machine — no signature requirement, no write-protected audit log. You can upgrade any time: run the setup again and pick a regulated profile.';
|
||
|
||
@override
|
||
String get setupScenTeamHub => 'A shared team hub';
|
||
|
||
@override
|
||
String get setupScenTeamHubSub =>
|
||
'A secured hub for several people — signed modules, resource limits.';
|
||
|
||
@override
|
||
String get setupScenRegulated => 'Regulated production';
|
||
|
||
@override
|
||
String get setupScenRegulatedSub =>
|
||
'Signed modules, a complete tamper-evident audit trail, and a human approval before every AI step.';
|
||
|
||
@override
|
||
String get setupScenBuildModules => 'Building modules';
|
||
|
||
@override
|
||
String get setupScenBuildModulesSub =>
|
||
'A developer setup for writing and testing your own modules.';
|
||
|
||
@override
|
||
String get setupIntentHello => 'Run the hello example';
|
||
|
||
@override
|
||
String get setupIntentHelloSub => 'Just see one flow run end to end.';
|
||
|
||
@override
|
||
String get setupIntentExtract => 'Extract text from documents';
|
||
|
||
@override
|
||
String get setupIntentExtractSub =>
|
||
'Pull plain text out of PDF and DOCX files.';
|
||
|
||
@override
|
||
String get setupIntentExtractSummarize => 'Extract and summarize';
|
||
|
||
@override
|
||
String get setupIntentExtractSummarizeSub =>
|
||
'Extract text, then summarize it.';
|
||
|
||
@override
|
||
String get setupIntentClassify => 'Sort incoming documents';
|
||
|
||
@override
|
||
String get setupIntentClassifySub =>
|
||
'Extract text, then classify it with an AI step.';
|
||
|
||
@override
|
||
String get setupIntentBuildModule => 'Build my own module';
|
||
|
||
@override
|
||
String get setupIntentBuildModuleSub => 'Start from a module scaffold.';
|
||
|
||
@override
|
||
String get setupTargetLaptop => 'This computer';
|
||
|
||
@override
|
||
String get setupTargetLaptopSub =>
|
||
'Runs locally on the machine you are on now.';
|
||
|
||
@override
|
||
String get setupTargetHomeServer => 'An on-premise server';
|
||
|
||
@override
|
||
String get setupTargetHomeServerSub =>
|
||
'A server in your own house — starts on boot, runs in the background.';
|
||
|
||
@override
|
||
String get setupTargetAirgapped => 'A fully local server (no internet)';
|
||
|
||
@override
|
||
String get setupTargetAirgappedSub =>
|
||
'An isolated server with no internet — the strictest, most private posture.';
|
||
|
||
@override
|
||
String get setupTargetContainer => 'A container';
|
||
|
||
@override
|
||
String get setupTargetContainerSub =>
|
||
'Docker or Podman, with a ready-made compose snippet.';
|
||
|
||
@override
|
||
String get setupApprovalPlain =>
|
||
'Ask a person for approval before every AI step';
|
||
|
||
@override
|
||
String get setupDataLocalPlain =>
|
||
'Data must never leave the building (fully local)';
|
||
|
||
@override
|
||
String get setupPlanIntroDev => 'Ch∆In sets up a straightforward workspace.';
|
||
|
||
@override
|
||
String get setupPlanIntroEnterprise =>
|
||
'Ch∆In sets up a secured operation for a team.';
|
||
|
||
@override
|
||
String get setupPlanIntroAirgapped =>
|
||
'Ch∆In sets up a fully local, regulated operation.';
|
||
|
||
@override
|
||
String get setupPlanSignatures => 'Only signed modules are allowed.';
|
||
|
||
@override
|
||
String get setupPlanWorm =>
|
||
'The audit log is additionally sealed tamper-proof (WORM).';
|
||
|
||
@override
|
||
String get setupPlanApproval =>
|
||
'Before every AI step, the system asks a person for approval.';
|
||
|
||
@override
|
||
String setupPlanModules(String modules) {
|
||
return 'These modules are prepared: $modules.';
|
||
}
|
||
|
||
@override
|
||
String setupPlanFlow(String flow) {
|
||
return 'An example flow “$flow” is created.';
|
||
}
|
||
|
||
@override
|
||
String setupPlanFileChanged(String path) {
|
||
return 'Only one file is changed: $path.';
|
||
}
|
||
|
||
@override
|
||
String get setupPlanOverwriteWarn =>
|
||
'An existing configuration will be overwritten.';
|
||
|
||
@override
|
||
String get setupApplied => 'Done — Ch∆In is set up.';
|
||
|
||
@override
|
||
String get setupNextTitle => 'Next steps';
|
||
|
||
@override
|
||
String get setupNextHubStart => 'Start the hub';
|
||
|
||
@override
|
||
String get setupHubRunning => 'The hub is running.';
|
||
|
||
@override
|
||
String get setupStartHubFirst =>
|
||
'Start the hub first — then the modules can be installed right here.';
|
||
|
||
@override
|
||
String setupActionInstall(String module) {
|
||
return 'Install $module';
|
||
}
|
||
|
||
@override
|
||
String setupActionInstalled(String module) {
|
||
return '$module is installed.';
|
||
}
|
||
|
||
@override
|
||
String setupActionOpenFlow(String flow) {
|
||
return 'Open the “$flow” example flow';
|
||
}
|
||
|
||
@override
|
||
String get setupModulesOfflineHint =>
|
||
'The modules arrive as an offline bundle, without internet — the documentation explains this under “running without internet”.';
|
||
|
||
@override
|
||
String get setupModulesSignedHint =>
|
||
'The modules come from your own, signed source — not from the public store.';
|
||
|
||
@override
|
||
String get setupSigPublicStoreNotice =>
|
||
'This setup only accepts signed modules. The public store currently ships unsigned bundles — the prepared modules therefore come from your own, signed source.';
|
||
|
||
@override
|
||
String get setupAllowUnsigned => 'Allow installing from the public store';
|
||
|
||
@override
|
||
String get setupAllowUnsignedSub =>
|
||
'Deliberately relaxes the signature requirement. Fine for trying things out — re-enable it for regulated operation.';
|
||
|
||
@override
|
||
String get setupStartCta => 'Start setup';
|
||
|
||
@override
|
||
String get setupGateIntro =>
|
||
'Before you start: three questions, then Ch∆In sets this machine up to match. Nothing changes without your confirmation.';
|
||
|
||
@override
|
||
String get setupGateSkip => 'Set up later';
|
||
|
||
@override
|
||
String get settingsRunSetup => 'Run setup again…';
|
||
|
||
@override
|
||
String get settingsRunSetupHint =>
|
||
'Opens the setup assistant (three questions, preview, apply). Your existing configuration is only replaced after you confirm.';
|
||
|
||
@override
|
||
String get setupPlanRunbookLocal =>
|
||
'This machine is being set up; the hub runs locally and starts on demand.';
|
||
|
||
@override
|
||
String get setupPlanRunbookService =>
|
||
'This machine is being set up: the hub will start automatically on boot (background service). For a different server, run the setup there.';
|
||
|
||
@override
|
||
String get setupPlanRunbookAirgap =>
|
||
'Intended for an isolated server without internet — modules and updates arrive as offline bundles.';
|
||
|
||
@override
|
||
String get setupPlanRunbookContainer =>
|
||
'Intended for container operation — a ready-made compose example is included.';
|
||
|
||
@override
|
||
String get setupPlanAuditChain =>
|
||
'Every step lands in a gapless, hash-chained audit log — tampering becomes detectable.';
|
||
|
||
@override
|
||
String setupPlanDocs(int n) {
|
||
return 'A matching reading list ($n chapters) is stored with the setup record under ~/.chain/.';
|
||
}
|
||
|
||
@override
|
||
String get setupTrustedPublishersHint =>
|
||
'Important: when adding the source, pin the publisher\'s key (\"pin signing key\") — otherwise the hub accepts any formally valid signature, no matter whose.';
|
||
|
||
@override
|
||
String get setupAddSignedSource => 'Add a signed source…';
|
||
|
||
@override
|
||
String get setupApplyNotes => 'Notes from the setup';
|
||
|
||
@override
|
||
String get setupFreeTextHint =>
|
||
'e.g.: pre-screen incoming applications and flag incomplete ones';
|
||
|
||
@override
|
||
String get setupFreeTextSuggest => 'Suggest a setup';
|
||
|
||
@override
|
||
String setupFreeTextPrivacyLocal(String model) {
|
||
return 'Your description is processed right on this machine — by the local AI model $model. Nothing leaves the device.';
|
||
}
|
||
|
||
@override
|
||
String setupFreeTextPrivacyRemote(String model, String provider) {
|
||
return 'Your description is sent to the configured system AI: $model ($provider).';
|
||
}
|
||
|
||
@override
|
||
String get setupFreeTextUnavailable =>
|
||
'The free-text path needs a configured system AI (Settings → System AI). The choices above always work — no AI required.';
|
||
|
||
@override
|
||
String setupExecHint(String path) {
|
||
return 'For the preview and setup, Studio runs the “chain” program: $path';
|
||
}
|
||
|
||
@override
|
||
String setupExecHintTcc(String path) {
|
||
return 'The program lives at $path — macOS may ask once for access to that folder (e.g. “Documents”). That is expected and fine.';
|
||
}
|
||
|
||
@override
|
||
String get setupNoBinaryStepHint =>
|
||
'The “chain” program could not be found on this machine — the preview in the next step will fail. You can pick it under “Doctor”, or install Ch∆In.';
|
||
|
||
@override
|
||
String get setupNoBinary =>
|
||
'The “chain” program could not be found on this machine.';
|
||
|
||
@override
|
||
String get setupNoBinaryHint =>
|
||
'Without it the assistant cannot apply the setup. Pick it under “Doctor”, or reinstall Ch∆In.';
|
||
|
||
@override
|
||
String get setupCliTooOld =>
|
||
'The installed “chain” program is older than Studio and does not know this assistant yet.';
|
||
|
||
@override
|
||
String setupCliTooOldHint(String path) {
|
||
return 'Found: $path. Please update Ch∆In (“Doctor” page → update, or in a terminal: chain update apply) and reopen the assistant afterwards.';
|
||
}
|
||
|
||
@override
|
||
String get setupPreviewFailed =>
|
||
'The plan preview could not be created — the “chain” program reported an error.';
|
||
|
||
@override
|
||
String get setupApplyFailed =>
|
||
'The setup could not be applied — the “chain” program reported an error.';
|
||
|
||
@override
|
||
String setupCliUsedBinary(String path) {
|
||
return 'Executed: $path';
|
||
}
|
||
|
||
@override
|
||
String get setupFreeTextParseError =>
|
||
'The system AI did not return a usable suggestion. Pick from the menu above — or try again.';
|
||
|
||
@override
|
||
String get setupReflectionTitle => 'This is how I read your task';
|
||
|
||
@override
|
||
String setupReflectionScenario(String label) {
|
||
return 'What it is about: $label';
|
||
}
|
||
|
||
@override
|
||
String setupReflectionIntent(String label) {
|
||
return 'First task: $label';
|
||
}
|
||
|
||
@override
|
||
String setupReflectionTarget(String label) {
|
||
return 'Environment: $label';
|
||
}
|
||
|
||
@override
|
||
String get setupReflectionApproval =>
|
||
'A human is asked for approval before every AI step.';
|
||
|
||
@override
|
||
String get setupReflectionDataLocal => 'Data never leaves the building.';
|
||
|
||
@override
|
||
String get setupReflectionEditHint =>
|
||
'Nothing is changed without your confirmation. Adjust any point, or go straight to the preview.';
|
||
|
||
@override
|
||
String get setupReflectionAdjust => 'Adjust';
|
||
|
||
@override
|
||
String get setupReflectionToPreview => 'To the preview';
|
||
|
||
@override
|
||
String get setupProfileDev => 'straightforward workstation';
|
||
|
||
@override
|
||
String get setupProfileEnterprise => 'hardened team operation';
|
||
|
||
@override
|
||
String get setupProfileAirgapped => 'fully local, regulated operation';
|
||
|
||
@override
|
||
String welcomeChecklistSetupDone(String profile) {
|
||
return 'The setup assistant already took care of the basics ($profile) — this list shows what has actually happened on your hub.';
|
||
}
|
||
}
|