From ceed8aab02663b53ba2b0897467f3499a6c984b5 Mon Sep 17 00:00:00 2001 From: flemming-it Date: Thu, 28 May 2026 14:15:39 +0200 Subject: [PATCH] feat(studio): temporal source bucket + provenance pill on store grid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the missing UI surface for SPARK / Temporal federated capabilities. Previously only mcp and n8n showed provenance pills; temporal-sourced entries fell through to the default "no badge" case. - storeSourceTemporal + storeProvenanceTemporal l10n keys (en + de). Pill format: "temporal · ", icon Icons.timer_outlined, accent tone. - Source filter chip row gains a "Temporal" option in the Store filter dialog. - `_StoreProvenancePill` adds a `case 'temporal'` branch. Operators federating a SPARK cluster (`services: - kind: temporal`) now see their workflows visually labelled as Temporal-sourced in the Store grid + filter UI. dart analyze green. No test changes required — the provenance pill is render-only. Signed-off-by: flemming-it --- lib/l10n/app_de.arb | 809 +++++++++++++++++++++++----- lib/l10n/app_en.arb | 813 ++++++++++++++++++++++++----- lib/l10n/app_localizations.dart | 12 + lib/l10n/app_localizations_de.dart | 8 + lib/l10n/app_localizations_en.dart | 8 + lib/pages/store.dart | 8 + 6 files changed, 1379 insertions(+), 279 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index a83d55e..c08aedd 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1,8 +1,6 @@ { "@@locale": "de", - "appTitle": "F∆I Studio", - "navWelcome": "Willkommen", "welcomeHeroTitle": "F∆I Platform", "welcomeHeroSubtitle": "Deterministische Workflow-Engine für KI-gestützte Dokumentenverarbeitung in regulierten Umgebungen.", @@ -31,7 +29,13 @@ "welcomeDocFlowsBlurb": "YAML-Grundlagen, Templating-Referenz, das Extract→Summarize-Beispiel.", "welcomeDocClose": "Schließen", "welcomeDocFailedToLoad": "Doku konnte nicht geladen werden: {error}", - "@welcomeDocFailedToLoad": { "placeholders": { "error": { "type": "String" } } }, + "@welcomeDocFailedToLoad": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "welcomeChecklistHeader": "ERSTE SCHRITTE", "welcomeChecklistBody": "Vier Schritte zu einem funktionierenden Hub. Live-Zustand — nach jeder Änderung aktualisieren.", "welcomeChecklistAi": "System-AI konfigurieren", @@ -54,12 +58,10 @@ "navFlows": "Flows", "navAudit": "Protokoll", "navApprovals": "Freigaben", - "connectionConnected": "verbunden", "connectionUnreachable": "nicht erreichbar", "connectionConnecting": "verbinde…", "connectionStartHub": "Hub starten", - "buttonCancel": "Abbrechen", "buttonSave": "Speichern", "buttonClose": "Schließen", @@ -80,8 +82,13 @@ "storeInstallableOnly": "Nur installierbare", "storePillComingSoon": "Bald verfügbar", "storeNotInstallableInline": "Dieses Modul ist auf der Roadmap (Status: {status}). Es gibt noch kein installierbares Bundle — Repository verfolgen für Updates.", - "@storeNotInstallableInline": { "placeholders": { "status": { "type": "String" } } }, - + "@storeNotInstallableInline": { + "placeholders": { + "status": { + "type": "String" + } + } + }, "mcpSuggestionDeepwikiDesc": "Öffentliches HTTPS — KI-gestützte Doku-Suche in GitHub-Repos. Kein Node, kein API-Key.", "mcpSuggestionSemgrepDesc": "Öffentliches HTTPS — Security-Scanning von Code-Schwachstellen. Kein Node, kein API-Key.", "mcpSuggestionFilesystemDesc": "Anthropic — Dateien in /tmp lesen / schreiben. Pfad vor dem Speichern anpassen.", @@ -94,12 +101,10 @@ "mcpSuggestionMemoryDesc": "Anthropic — persistenter Knowledge-Graph als Agenten-Gedächtnis.", "mcpSuggestionTimeDesc": "Anthropic — aktuelle Uhrzeit + Zeitzonen-Konvertierung.", "mcpServerEnLanguageBadge": "Server-Text in Englisch — Studio zeigt ihn wie geliefert.", - "themePluginHeader": "Theme-Plugin", "themePluginNone": "Standard (kein Plugin)", "themePluginHint": "Installiertes studio.theme.*-Plugin auswählen, um das ganze Studio umzustylen. Erst eines aus dem Store installieren.", "themePluginEmpty": "Kein Theme-Plugin installiert. Im Store eines aus der Kategorie studio-plugin auswählen.", - "settingsTitle": "Hub-Endpunkt", "settingsHost": "Host", "settingsPort": "Port", @@ -119,16 +124,40 @@ "systemAiConfigure": "Konfigurieren…", "systemAiOffBlurb": "Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicke Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.", "mcpServersCount": "{n} {n, plural, =1{Server} other{Server}}", - "@mcpServersCount": { "placeholders": { "n": { "type": "int" } } }, + "@mcpServersCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "mcpRediscoverTooltip": "Discovery neu ausführen", "mcpAddTooltip": "MCP-Server hinzufügen", "mcpRemoveTooltip": "Server entfernen", "mcpToolsCount": "{n} Tools", - "@mcpToolsCount": { "placeholders": { "n": { "type": "int" } } }, + "@mcpToolsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nEndpointsCount": "{n} {n, plural, =1{Endpunkt} other{Endpunkte}}", - "@n8nEndpointsCount": { "placeholders": { "n": { "type": "int" } } }, + "@n8nEndpointsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nWorkflowsCount": "{n} Workflows", - "@n8nWorkflowsCount": { "placeholders": { "n": { "type": "int" } } }, + "@n8nWorkflowsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nRediscoverTooltip": "Discovery neu ausführen", "n8nAddTooltip": "n8n-Endpunkt hinzufügen", "n8nRemoveTooltip": "Endpunkt entfernen", @@ -154,16 +183,45 @@ "addN8nNotesLabel": "Notizen (optional)", "addN8nAddButton": "Hinzufügen + Discovery", "addedMcpToast": "MCP-Server „{name}\" hinzugefügt.", - "@addedMcpToast": { "placeholders": { "name": { "type": "String" } } }, + "@addedMcpToast": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "addedN8nToast": "n8n-Endpunkt „{name}\" hinzugefügt.", - "@addedN8nToast": { "placeholders": { "name": { "type": "String" } } }, + "@addedN8nToast": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "addFailedToast": "Hinzufügen fehlgeschlagen: {error}", - "@addFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@addFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "removeFailedToast": "Entfernen fehlgeschlagen: {error}", - "@removeFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@removeFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "refreshFailedToast": "Aktualisieren fehlgeschlagen: {error}", - "@refreshFailedToast": { "placeholders": { "error": { "type": "String" } } }, - + "@refreshFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "channelsHeader": "KANÄLE", "channelsActive": "aktiv", "channelsRunning": "läuft", @@ -172,7 +230,6 @@ "channelsSwitch": "Diesen Kanal aktivieren", "channelsEnableAutostart": "Autostart bei Anmeldung aktivieren", "channelsDisableAutostart": "Autostart deaktivieren", - "storeSearchHint": "Module suchen — Name, Tagline, Tag, Fähigkeit…", "storeAskHint": "Was brauchst du? Versuch's mit „ein Modul, das tabellarische Daten liest\" oder tippe einfach einen Begriff.", "storeAskSubmit": "Suchen", @@ -186,7 +243,13 @@ "storeAskMatchPill": "Treffer", "storeFilterLabel": "Filter", "storeFilterActiveCount": "{n} aktiv", - "@storeFilterActiveCount": { "placeholders": { "n": { "type": "int" } } }, + "@storeFilterActiveCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "storeFilterReset": "Filter zurücksetzen", "storeFilterApply": "Fertig", "storeFilterStatusGroup": "Status", @@ -216,7 +279,11 @@ "storeCategoryOrchestrator": "Orchestrierung", "storeNResults": "{n} Treffer", "@storeNResults": { - "placeholders": { "n": { "type": "int" } } + "placeholders": { + "n": { + "type": "int" + } + } }, "storeReloadTooltip": "Aktualisieren", "storeTodayBadge": "HEUTE", @@ -225,38 +292,80 @@ "storePillInstalled": "installiert", "storePillUpdate": "Update", "storeUpdateButton": "Update auf {version}", - "@storeUpdateButton": { "placeholders": { "version": { "type": "String" } } }, + "@storeUpdateButton": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "storeUpdateTooltip": "Installiert {installed} — Store bietet v{best}", "@storeUpdateTooltip": { "placeholders": { - "installed": { "type": "String" }, - "best": { "type": "String" } + "installed": { + "type": "String" + }, + "best": { + "type": "String" + } } }, "storeNoTagline": "(keine Beschreibung)", "storeUninstallTitle": "Modul deinstallieren?", "storeUninstallBody": "Entfernt {name} aus diesem Hub. Flows, die es verwenden, schlagen beim nächsten Lauf fehl.", - "@storeUninstallBody": { "placeholders": { "name": { "type": "String" } } }, + "@storeUninstallBody": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "storeInstalledToast": "{name} v{version} installiert.", "@storeInstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "storeInstallFailedToast": "Installation fehlgeschlagen: {error}", - "@storeInstallFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@storeInstallFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeUninstalledToast": "{name} v{version} deinstalliert.", "@storeUninstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "storeUninstallFailedToast": "Deinstallation fehlgeschlagen: {error}", - "@storeUninstallFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@storeUninstallFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeOpenBrowserFailed": "Browser konnte nicht geöffnet werden: {error}", - "@storeOpenBrowserFailed": { "placeholders": { "error": { "type": "String" } } }, + "@storeOpenBrowserFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeSectionTags": "Tags", "storeSectionRequiredCapabilities": "Erforderliche Fähigkeiten", "storeSectionRequiredHostServices": "Erforderliche Host-Dienste", @@ -269,9 +378,21 @@ "storeInstallingButton": "Installiere…", "storeNotInstallable": "Nicht installierbar", "storeNotInstallableTooltip": "Status „{status}\" — Installations-Pfad noch nicht verdrahtet.", - "@storeNotInstallableTooltip": { "placeholders": { "status": { "type": "String" } } }, + "@storeNotInstallableTooltip": { + "placeholders": { + "status": { + "type": "String" + } + } + }, "storeInstallProgressTitle": "Installation von {name}", - "@storeInstallProgressTitle": { "placeholders": { "name": { "type": "String" } } }, + "@storeInstallProgressTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "storeInstallProgressBody": "Holen, verifizieren, entpacken…", "storeLoadDocs": "Dokumentation laden", "storeDocsHint": "README inline gerendert; nutzt das Registry-Token des Hubs, falls nötig.", @@ -281,7 +402,13 @@ "storeDocsErrorNoDocs": "Für dieses Modul ist keine Repository-URL hinterlegt.", "storeDocsErrorAuth": "Die Registry erfordert Authentifizierung, um dieses README zu laden. Setze FAI_REGISTRY_TOKEN in der Umgebung des Daemons und starte den Hub neu.", "storeDocsErrorNetwork": "Netzwerkfehler beim Laden des README. {detail}", - "@storeDocsErrorNetwork": { "placeholders": { "detail": { "type": "String" } } }, + "@storeDocsErrorNetwork": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "storeDocsErrorParse": "README ist kein gültiges UTF-8.", "storeDocsErrorGeneric": "README konnte nicht geladen werden.", "storeSourceLabel": "Quelle", @@ -291,9 +418,21 @@ "storeSourceN8n": "n8n", "storeProvenanceNative": "nativ", "storeProvenanceMcp": "mcp · {provider}", - "@storeProvenanceMcp": { "placeholders": { "provider": { "type": "String" } } }, + "@storeProvenanceMcp": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, "storeProvenanceN8n": "n8n · {provider}", - "@storeProvenanceN8n": { "placeholders": { "provider": { "type": "String" } } }, + "@storeProvenanceN8n": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, "storeRecommendedTitle": "Öffentliche Quelle hinzufügen — ein Klick", "storeRecommendedBody": "Kuratierte MCP-Server über HTTPS erreichbar. Kein Subprozess, kein API-Key, kein Node. Föderierte Fähigkeiten erscheinen sofort im Store.", "storeRecommendedAddTooltip": "Hinzufügen und entdecken", @@ -303,22 +442,33 @@ "storeProviderAddedToast": "{name} hinzugefügt — {n} {n, plural, =1{föderierte Fähigkeit} other{föderierte Fähigkeiten}}.", "@storeProviderAddedToast": { "placeholders": { - "name": { "type": "String" }, - "n": { "type": "int" } + "name": { + "type": "String" + }, + "n": { + "type": "int" + } } }, "storeProviderAddedZeroToast": "{name} ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffne Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.", "@storeProviderAddedZeroToast": { - "placeholders": { "name": { "type": "String" } } + "placeholders": { + "name": { + "type": "String" + } + } }, "storeProviderAddFailed": "{name} konnte nicht hinzugefügt werden: {error}", "@storeProviderAddFailed": { "placeholders": { - "name": { "type": "String" }, - "error": { "type": "String" } + "name": { + "type": "String" + }, + "error": { + "type": "String" + } } }, - "auditTitle": "Protokoll", "auditNoEvents": "Noch keine Ereignisse", "auditNoEventsHint": "Starte einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.", @@ -330,26 +480,60 @@ "auditClearedToast": "{n} Ereignisse auf Kanal „{channel}\" gelöscht. Kette mit Marker neu geseedet.", "@auditClearedToast": { "placeholders": { - "n": { "type": "int" }, - "channel": { "type": "String" } + "n": { + "type": "int" + }, + "channel": { + "type": "String" + } } }, "auditClearFailed": "Löschen fehlgeschlagen: {detail}", - "@auditClearFailed": { "placeholders": { "detail": { "type": "String" } } }, + "@auditClearFailed": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "auditExplain": "Erklären", "auditReask": "Neu fragen", "auditAsking": "Frage läuft…", "auditSystemAi": "SYSTEM-AI", "auditCachedPill": "gecacht", "auditOriginalLatency": "ursprünglich {ms} ms", - "@auditOriginalLatency": { "placeholders": { "ms": { "type": "int" } } }, + "@auditOriginalLatency": { + "placeholders": { + "ms": { + "type": "int" + } + } + }, "auditLatency": "{ms} ms", - "@auditLatency": { "placeholders": { "ms": { "type": "int" } } }, + "@auditLatency": { + "placeholders": { + "ms": { + "type": "int" + } + } + }, "auditRegenerateTooltip": "Neu generieren — Cache überspringen, Modell erneut fragen", "auditLiveStatus": "live · Abfrage alle 2s · {n} {n, plural, =1{Ereignis} other{Ereignisse}}", - "@auditLiveStatus": { "placeholders": { "n": { "type": "int" } } }, + "@auditLiveStatus": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "auditDisconnected": "getrennt · {error}", - "@auditDisconnected": { "placeholders": { "error": { "type": "String" } } }, + "@auditDisconnected": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "auditHashChainVerified": "Hash-Kette verifiziert", "auditDetailHeader": "DETAIL", "auditAskingFull": "Frage an die konfigurierte System-AI läuft…", @@ -357,14 +541,30 @@ "auditCachedTooltipKnown": "Aus dem lokalen Cache geliefert. Ursprünglich erzeugt am {at}{hits}.", "@auditCachedTooltipKnown": { "placeholders": { - "at": { "type": "String" }, - "hits": { "type": "String" } + "at": { + "type": "String" + }, + "hits": { + "type": "String" + } } }, "auditCachedTooltipUnknown": "Aus dem lokalen Cache geliefert. Ursprünglicher Zeitpunkt unbekannt{hits}.", - "@auditCachedTooltipUnknown": { "placeholders": { "hits": { "type": "String" } } }, + "@auditCachedTooltipUnknown": { + "placeholders": { + "hits": { + "type": "String" + } + } + }, "auditCachedTooltipHits": " · {n} Treffer", - "@auditCachedTooltipHits": { "placeholders": { "n": { "type": "int" } } }, + "@auditCachedTooltipHits": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "auditConfigureSystemAi": "System-AI unter Einstellungen konfigurieren (Cmd+,)", "auditClearDialogTitle": "Audit-Log löschen?", "auditClearDialogBody": "Löscht jedes Audit-Event auf dem aktiven Kanal und seedet einen neuen chain.reset-Marker mit Prüfer und Begründung. Auf beta / production verweigert. Nicht umkehrbar.", @@ -372,14 +572,19 @@ "auditClearReasonLabel": "Begründung (im chain.reset-Marker festgehalten)", "auditClearReasonHelper": "Erforderlich — Auditoren werden das lesen.", "auditClearLogButton": "Log löschen", - "modulesTitle": "Module", "modulesNoneTitle": "Noch keine Module", "modulesNoneHint": "`fai install ` ausführen oder ~/.fai/modules/ prüfen.", "modulesReloadTooltip": "Aktualisieren", "modulesRecentActivity": "LETZTE AKTIVITÄT", "modulesRecentActivityHint": "letzte {n} install/uninstall-Ereignisse aus dem Audit-Log", - "@modulesRecentActivityHint": { "placeholders": { "n": { "type": "int" } } }, + "@modulesRecentActivityHint": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "modulesActivityInstalled": "installiert", "modulesActivityUninstalled": "deinstalliert", "modulesCapabilitiesLabel": "Fähigkeiten", @@ -387,32 +592,57 @@ "modulesUninstallBody": "Entfernt {name} v{version} von diesem Hub. Flows, die es verwenden, schlagen beim nächsten Lauf fehl. Ein `module.uninstalled`-Audit-Event wird festgehalten.", "@modulesUninstallBody": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "modulesUninstalledToast": "{name} v{version} deinstalliert.", "@modulesUninstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "modulesUninstallFailed": "Deinstallation fehlgeschlagen: {error}", - "@modulesUninstallFailed": { "placeholders": { "error": { "type": "String" } } }, + "@modulesUninstallFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "modulesUninstalling": "Wird deinstalliert…", "moduleSheetFailedToLoad": "Laden fehlgeschlagen: {error}", - "@moduleSheetFailedToLoad": { "placeholders": { "error": { "type": "String" } } }, + "@moduleSheetFailedToLoad": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "moduleSheetCapabilities": "Fähigkeiten", "moduleSheetPermissions": "Deklarierte Berechtigungen", "moduleSheetNoPermissions": "(keine — reines Berechnungsmodul)", - "flowsTitle": "Flows", "flowsReloadTooltip": "Aktualisieren", "flowsNoneTitle": "Keine gespeicherten Flows", "flowsNoneHint": "Flow speichern mit `fai admin flows save `, dann taucht er hier auf.", "flowsRunDialogTitle": "{name} ausführen", - "@flowsRunDialogTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsRunDialogTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsRunDialogBody": "Pro deklariertem Input ein Feld. Bytes-Inputs öffnen einen Datei-Picker; alle anderen sind Klartext. Der Starten-Button aktiviert sich, wenn alle Pflichtfelder gefüllt sind.", "flowsLoadingDefinition": "Inputs werden geladen…", "flowsDefinitionFailed": "Flow-Definition konnte nicht geladen werden", @@ -421,47 +651,89 @@ "flowsTypeBytesChange": "Datei ändern", "flowsTypeBytesNoFile": "Keine Datei ausgewählt", "flowsTypeBytesSize": "{n} Bytes", - "@flowsTypeBytesSize": { "placeholders": { "n": { "type": "int" } } }, + "@flowsTypeBytesSize": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "flowsRunErrorTitle": "Flow-Lauf fehlgeschlagen", "flowsFileReadFailed": "„{path}\" konnte nicht gelesen werden: {error}", "@flowsFileReadFailed": { "placeholders": { - "path": { "type": "String" }, - "error": { "type": "String" } + "path": { + "type": "String" + }, + "error": { + "type": "String" + } } }, "flowsMissingModulesLabel": "Braucht:", "flowsRunDisabledTooltip": "Erst die fehlenden Module installieren.", "flowsInstallAllButton": "Alle installieren ({n})", - "@flowsInstallAllButton": { "placeholders": { "n": { "type": "int" } } }, + "@flowsInstallAllButton": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "flowsInstallPillTooltip": "Zum Installieren klicken", "flowsInstallDepsTitle": "Abhängigkeiten installieren", "flowsInstallDepsBody": "Die fehlenden Module werden der Reihe nach installiert. Vorhandene Installationen bleiben unberührt.", "flowsInstallStatusPending": "Wartet", "flowsInstallStatusInstalling": "Wird installiert…", "flowsInstallStatusDone": "Installiert v{version}", - "@flowsInstallStatusDone": { "placeholders": { "version": { "type": "String" } } }, + "@flowsInstallStatusDone": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "flowsInstallStatusFailed": "Fehlgeschlagen", "flowsInstallStatusFailedDetail": "{error}", - "@flowsInstallStatusFailedDetail": { "placeholders": { "error": { "type": "String" } } }, + "@flowsInstallStatusFailedDetail": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "flowsInstallDepsAllDone": "Alle Abhängigkeiten installiert.", "flowsInstallDepsAnyFailed": "{ok} installiert, {failed} fehlgeschlagen.", "@flowsInstallDepsAnyFailed": { "placeholders": { - "ok": { "type": "int" }, - "failed": { "type": "int" } + "ok": { + "type": "int" + }, + "failed": { + "type": "int" + } } }, "flowsInstallAuthWallButton": "Registry-Token einfügen", "flowsOpenInEditorTooltip": "YAML-Datei im Standard-Editor öffnen", "flowsOpenInEditorFailed": "Konnte Datei nicht öffnen: {error}", "@flowsOpenInEditorFailed": { - "placeholders": { "error": { "type": "String" } } + "placeholders": { + "error": { + "type": "String" + } + } }, "registryCredentialsHeader": "REGISTRY-ZUGANGSDATEN", "registryCredentialsBlurb": "Token zum Herunterladen von .fai-Modulen aus einer Registry mit Anmeldepflicht (Forgejo, private GitHub-Repos). Gespeichert in ~/.fai/registry-token, Modus 0600. Die Umgebungsvariable FAI_REGISTRY_TOKEN hat weiterhin Vorrang, wenn gesetzt.", "registryTokenStatusConfigured": "Konfiguriert ({chars} Zeichen)", - "@registryTokenStatusConfigured": { "placeholders": { "chars": { "type": "int" } } }, + "@registryTokenStatusConfigured": { + "placeholders": { + "chars": { + "type": "int" + } + } + }, "registryTokenStatusNotSet": "Nicht gesetzt", "registryTokenFieldLabel": "Token", "registryTokenFieldHint": "Forgejo- oder GitHub-PAT einfügen", @@ -472,7 +744,11 @@ "registryTokenClearedToast": "Registry-Token entfernt.", "registryTokenSaveFailedToast": "Speichern fehlgeschlagen: {error}", "@registryTokenSaveFailedToast": { - "placeholders": { "error": { "type": "String" } } + "placeholders": { + "error": { + "type": "String" + } + } }, "maintenanceHeader": "HUB-WARTUNG", "maintenanceResetBlurb": "Operator-Zustand zurücksetzen und mit einem sauberen Hub neu starten. Stoppt jeden laufenden Daemon, sichert ~/.fai/ atomar in ein Backup, legt es dann neu an — Binary, Channel-Pointer, MCP-/n8n-/System-AI-Konfiguration und Registry-Token bleiben erhalten. Wiederherstellen durch Zurückverschieben des Backup-Ordners.", @@ -502,41 +778,90 @@ "auditGroupOlder": "ÄLTER", "auditEventViewFlowRun": "Flow-Lauf ansehen", "auditFlowRunDialogTitle": "Flow-Lauf · {flow}", - "@auditFlowRunDialogTitle": { "placeholders": { "flow": { "type": "String" } } }, + "@auditFlowRunDialogTitle": { + "placeholders": { + "flow": { + "type": "String" + } + } + }, "auditFlowRunDialogSubtitle": "{n} {n, plural, =1{Ereignis} other{Ereignisse}} für Lauf {execution}", "@auditFlowRunDialogSubtitle": { "placeholders": { - "n": { "type": "int" }, - "execution": { "type": "String" } + "n": { + "type": "int" + }, + "execution": { + "type": "String" + } } }, "approvalsSelectAll": "Alle wählen", "approvalsClearSelection": "Auswahl aufheben", "approvalsBatchSelected": "{n} ausgewählt", - "@approvalsBatchSelected": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchSelected": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchApprove": "Alle freigeben", "approvalsBatchReject": "Alle ablehnen", "approvalsBatchApproveDoneToast": "{n} Freigaben erteilt.", - "@approvalsBatchApproveDoneToast": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchApproveDoneToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchRejectDoneToast": "{n} Freigaben abgelehnt.", - "@approvalsBatchRejectDoneToast": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchRejectDoneToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchPartialFailure": "{ok} erledigt, {failed} fehlgeschlagen.", "@approvalsBatchPartialFailure": { "placeholders": { - "ok": { "type": "int" }, - "failed": { "type": "int" } + "ok": { + "type": "int" + }, + "failed": { + "type": "int" + } } }, "flowsRunButton": "Starten", "flowsRunningTitle": "{name} läuft", - "@flowsRunningTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsRunningTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsResultTitle": "{name} — Ergebnis", - "@flowsResultTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsResultTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsErrorTitle": "{name} — fehlgeschlagen", - "@flowsErrorTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsErrorTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsRunning": "Flow läuft…", "flowsNoOutputs": "Flow abgeschlossen ohne deklarierte Outputs.", - "errGeneric": "Da ist etwas schiefgegangen.", "errInvalidArgument": "Ungültige Eingabe.", "errInvalidArgumentHint": "Werte im Formular prüfen und erneut versuchen.", @@ -560,13 +885,30 @@ "flowsOutputSaveAs": "Speichern unter…", "flowsOutputSaveAsTitle": "Flow-Output speichern", "flowsOutputSavedAt": "Gespeichert: {path}", - "@flowsOutputSavedAt": { "placeholders": { "path": { "type": "String" } } }, + "@flowsOutputSavedAt": { + "placeholders": { + "path": { + "type": "String" + } + } + }, "flowsOutputSaveFailed": "Speichern fehlgeschlagen: {error}", - "@flowsOutputSaveFailed": { "placeholders": { "error": { "type": "String" } } }, + "@flowsOutputSaveFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "flowsOutputOpen": "Öffnen", "flowsOutputOpenFailed": "Öffnen fehlgeschlagen: {error}", - "@flowsOutputOpenFailed": { "placeholders": { "error": { "type": "String" } } }, - + "@flowsOutputOpenFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsTitle": "Freigaben", "approvalsTabPending": "Offen", "approvalsTabHistory": "Verlauf", @@ -585,21 +927,41 @@ "approvalsApprovedToast": "freigegeben · {flow} › {step}", "@approvalsApprovedToast": { "placeholders": { - "flow": { "type": "String" }, - "step": { "type": "String" } + "flow": { + "type": "String" + }, + "step": { + "type": "String" + } } }, "approvalsRejectedToast": "abgelehnt · {flow} › {step}", "@approvalsRejectedToast": { "placeholders": { - "flow": { "type": "String" }, - "step": { "type": "String" } + "flow": { + "type": "String" + }, + "step": { + "type": "String" + } } }, "approvalsApproveFailed": "Freigabe fehlgeschlagen: {error}", - "@approvalsApproveFailed": { "placeholders": { "error": { "type": "String" } } }, + "@approvalsApproveFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsRejectFailed": "Ablehnung fehlgeschlagen: {error}", - "@approvalsRejectFailed": { "placeholders": { "error": { "type": "String" } } }, + "@approvalsRejectFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsHistoryEmpty": "Noch kein Verlauf", "approvalsHistoryEmptyHint": "Entschiedene Freigaben (freigegeben / abgelehnt / abgelaufen) erscheinen hier.\nDas Audit-Log enthält den vollständigen hash-verketteten Datensatz.", "approvalsDialogDecided": "entschieden", @@ -607,36 +969,67 @@ "approvalsDialogReason": "Begründung", "approvalsDialogPrompt": "PROMPT", "approvalsExpiresIn": "{minutes}m", - "@approvalsExpiresIn": { "placeholders": { "minutes": { "type": "int" } } }, + "@approvalsExpiresIn": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, "approvalsExpiresInHours": "{hours}h", - "@approvalsExpiresInHours": { "placeholders": { "hours": { "type": "int" } } }, - + "@approvalsExpiresInHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, "doctorTitle": "Diagnose", "doctorSummaryModules": "Module", "doctorSummaryApprovals": "Freigaben", "doctorSummaryAudit": "Protokoll", "doctorSummaryServices": "Dienste", "doctorSummaryCapabilities": "{n} Fähigkeiten", - "@doctorSummaryCapabilities": { "placeholders": { "n": { "type": "int" } } }, + "@doctorSummaryCapabilities": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorSummaryPending": "offen", "doctorSummaryChain": "{verified}/{total} Kette", "@doctorSummaryChain": { "placeholders": { - "verified": { "type": "int" }, - "total": { "type": "int" } + "verified": { + "type": "int" + }, + "total": { + "type": "int" + } } }, "doctorSummaryDeclared": "deklariert", "doctorModulesPanelSummary": "{n} Module · {m} Fähigkeiten", "@doctorModulesPanelSummary": { "placeholders": { - "n": { "type": "int" }, - "m": { "type": "int" } + "n": { + "type": "int" + }, + "m": { + "type": "int" + } } }, "doctorApprovalsNone": "Keine offenen Freigaben", "doctorApprovalsCount": "{n, plural, =1{1 Freigabe wartet auf Prüfung} other{{n} Freigaben warten auf Prüfung}}", - "@doctorApprovalsCount": { "placeholders": { "n": { "type": "int" } } }, + "@doctorApprovalsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorApprovalsAttentionPill": "wichtig", "doctorServicesEmpty": "Keine Host-Dienste deklariert", "doctorServicesEmptyHint": "in ~/.fai/config.yaml unter services: hinzufügen", @@ -650,14 +1043,26 @@ "doctorDaemonControlSection": "Daemon-Steuerung", "doctorChainIntact": "Hash-Kette intakt", "doctorChainIntactDetail": "{n} Ereignisse · prev_event_sha256 lückenlos verifiziert", - "@doctorChainIntactDetail": { "placeholders": { "n": { "type": "int" } } }, + "@doctorChainIntactDetail": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorChainTampered": "Manipulation erkannt", "doctorChainTamperedDetail": "{verified} von {total} verifiziert vor Mismatch bei {id}", "@doctorChainTamperedDetail": { "placeholders": { - "verified": { "type": "int" }, - "total": { "type": "int" }, - "id": { "type": "String" } + "verified": { + "type": "int" + }, + "total": { + "type": "int" + }, + "id": { + "type": "String" + } } }, "doctorChainPillOk": "WORM-1", @@ -670,12 +1075,22 @@ "doctorRunningOn": "Läuft auf {name}: {endpoint}", "@doctorRunningOn": { "placeholders": { - "name": { "type": "String" }, - "endpoint": { "type": "String" } + "name": { + "type": "String" + }, + "endpoint": { + "type": "String" + } } }, "doctorStoppedOn": "{name}-Daemon gestoppt", - "@doctorStoppedOn": { "placeholders": { "name": { "type": "String" } } }, + "@doctorStoppedOn": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "doctorStatusUnknown": "Daemon-Status: …", "doctorPillRunning": "läuft", "doctorPillStopped": "gestoppt", @@ -689,40 +1104,64 @@ "doctorPathPid": "PID-Datei", "doctorPathsEmpty": "Daemon hat keine Datei-Pfade gemeldet. Hub aktualisieren via `fai daemon restart`.", "doctorOpenError": "Konnte nicht öffnen: {detail}", - "@doctorOpenError": { "placeholders": { "detail": { "type": "String" } } }, + "@doctorOpenError": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "doctorUpdateAvailable": "Update verfügbar — {version}", - "@doctorUpdateAvailable": { "placeholders": { "version": { "type": "String" } } }, + "@doctorUpdateAvailable": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "doctorUpdateBody": "Kanal {channel} bietet jetzt {version}. Per Button anwenden — Studio ruft `fai update apply --channel {channel}` auf.", "@doctorUpdateBody": { "placeholders": { - "channel": { "type": "String" }, - "version": { "type": "String" } + "channel": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "doctorUpdateUnreachable": "Release-Host nicht erreichbar", "doctorUpdateUnreachableBody": "Release-Feed für {channel} konnte nicht erreicht werden.", - "@doctorUpdateUnreachableBody": { "placeholders": { "channel": { "type": "String" } } }, + "@doctorUpdateUnreachableBody": { + "placeholders": { + "channel": { + "type": "String" + } + } + }, "doctorReleaseNotes": "Notes: {url}", - "@doctorReleaseNotes": { "placeholders": { "url": { "type": "String" } } }, + "@doctorReleaseNotes": { + "placeholders": { + "url": { + "type": "String" + } + } + }, "doctorPillNew": "neu", "doctorPillOffline": "offline", "doctorApplyUpdate": "Update anwenden", "doctorApplying": "Wird angewendet…", "doctorApplyDone": "Update angewendet. Studio neu starten, um die neue Daemon-Version zu sehen.", - "mcpHeader": "MCP-CLIENTS", "mcpHint": "Externe MCP-Server bringen ihre Tools als `mcp..` Fähigkeiten ein. Einmal konfigurieren, im Store sichtbar.", "mcpEmpty": "Keine MCP-Server konfiguriert. + klicken zum Hinzufügen.", "n8nHeader": "N8N-ENDPUNKTE", "n8nHint": "Aktive n8n-Workflows erscheinen als `n8n..` Fähigkeiten. Einmal konfigurieren, im Store sichtbar.", "n8nEmpty": "Keine n8n-Endpunkte konfiguriert. + klicken zum Hinzufügen.", - "hubUnreachable": "Hub nicht erreichbar", "hubUnreachableHint": "Hub starten mit `fai serve`.", - "languageEnglish": "English", "languageGerman": "Deutsch", - "searchHint": "Springe überall hin — Module, Store, Flows, Seiten…", "searchIndexing": "Indiziere…", "searchNoMatches": "Keine Treffer.", @@ -735,17 +1174,40 @@ "searchGroupFlows": "Flows", "searchSettingsLabel": "Einstellungen", "searchPageHint": "Seite · ⌘{n}", - "@searchPageHint": { "placeholders": { "n": { "type": "int" } } }, + "@searchPageHint": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "searchSettingsHint": "Hub-Endpunkt, Kanäle, System-AI · ⌘;", "searchInstalledModuleHint": "installiertes Modul · v{version}", - "@searchInstalledModuleHint": { "placeholders": { "version": { "type": "String" } } }, + "@searchInstalledModuleHint": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "searchStoreUncategorized": "ohne Kategorie", "searchStoreHintWithTagline": "Store · {tagline}", - "@searchStoreHintWithTagline": { "placeholders": { "tagline": { "type": "String" } } }, + "@searchStoreHintWithTagline": { + "placeholders": { + "tagline": { + "type": "String" + } + } + }, "searchStoreHintWithCategory": "Store · {category}", - "@searchStoreHintWithCategory": { "placeholders": { "category": { "type": "String" } } }, + "@searchStoreHintWithCategory": { + "placeholders": { + "category": { + "type": "String" + } + } + }, "searchSavedFlowHint": "gespeicherter Flow", - "systemAiTitle": "System-AI", "systemAiIntro": "Die hub-interne LLM, die die Plattform selbst für Fehlererklärungen und Operator-Hilfe nutzt. Standardmäßig aus; hier konfigurieren. Siehe docs/architecture/system-ai.md, was über die Leitung geht.", "systemAiProviderLabel": "Provider", @@ -753,7 +1215,13 @@ "systemAiApiKeyRequired": "API-Key-Umgebungsvariable (erforderlich)", "systemAiApiKeyOptional": "API-Key-Umgebungsvariable (optional)", "systemAiApiKeyDisclaimer": "Studio liest oder speichert den Key-Wert nie — nur den Namen der Umgebungsvariable. Der Hub liest `${name}` zur Anfragezeit.", - "@systemAiApiKeyDisclaimer": { "placeholders": { "name": { "type": "String" } } }, + "@systemAiApiKeyDisclaimer": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "systemAiTestConnection": "Verbindung testen", "systemAiTesting": "Teste…", "systemAiSave": "Speichern", @@ -767,7 +1235,13 @@ "systemAiConnectionOk": "Verbindung ok", "systemAiConnectionFailed": "Verbindung fehlgeschlagen", "systemAiReplyPrefix": "Antwort: {text}", - "@systemAiReplyPrefix": { "placeholders": { "text": { "type": "String" } } }, + "@systemAiReplyPrefix": { + "placeholders": { + "text": { + "type": "String" + } + } + }, "systemAiModelLabel": "Modell (erforderlich)", "systemAiModelHintFallback": "Modell-Identifier, den der Provider erwartet", "systemAiModelHelperBase": "Erforderlich: aus der Liste auswählen (Aktualisieren) oder eintippen.", @@ -776,7 +1250,13 @@ "systemAiPull": "Pull", "systemAiPulling": "Lade…", "systemAiCouldNotListModels": "Modelle konnten nicht aufgelistet werden: {error}", - "@systemAiCouldNotListModels": { "placeholders": { "error": { "type": "String" } } }, + "@systemAiCouldNotListModels": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "systemAiNoModelsOllama": "Noch keine Modelle auf dem Ollama-Server. Oben eintippen und Pull klicken.", "systemAiNoModelsGeneric": "Provider lieferte keine Modelle.", "systemAiSuitabilityRecommended": "empfohlen", @@ -786,23 +1266,74 @@ "systemAiSuitabilityHuge": "sehr groß — auf einem Laptop wahrscheinlich zu langsam", "systemAiSuitabilityUnknown": "Größe unbekannt", "systemAiHwDetected": "Erkannt: {summary}", - "@systemAiHwDetected": { "placeholders": { "summary": { "type": "String" } } }, + "@systemAiHwDetected": { + "placeholders": { + "summary": { + "type": "String" + } + } + }, "systemAiHwReviewed": " · Kuratierung geprüft {date}", - "@systemAiHwReviewed": { "placeholders": { "date": { "type": "String" } } }, + "@systemAiHwReviewed": { + "placeholders": { + "date": { + "type": "String" + } + } + }, "systemAiLegendRecommended": "empfohlen für diese Hardware{tier}", - "@systemAiLegendRecommended": { "placeholders": { "tier": { "type": "String" } } }, + "@systemAiLegendRecommended": { + "placeholders": { + "tier": { + "type": "String" + } + } + }, "systemAiLegendBalanced": "ausgewogen (4-8B)", "systemAiLegendSmallLarge": "klein <3B / groß 9-15B / über Hardware", "systemAiLegendHuge": "sehr groß >15B", "systemAiLegendUnknown": "Größe unbekannt", "systemAiCacheRow": "Cache: {n} {n, plural, =1{gespeicherte Erklärung} other{gespeicherte Erklärungen}}. Identische Prompts treffen den Cache; Modell- oder Privacy-Modus-Wechsel leeren ihn automatisch.", - "@systemAiCacheRow": { "placeholders": { "n": { "type": "int" } } }, + "@systemAiCacheRow": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "systemAiCacheClear": "Leeren", "systemAiCacheClearedToast": "{n} gespeicherte System-AI-Erklärungen gelöscht.", - "@systemAiCacheClearedToast": { "placeholders": { "n": { "type": "int" } } }, + "@systemAiCacheClearedToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "systemAiCacheClearFailed": "Cache-Löschen fehlgeschlagen: {error}", - "@systemAiCacheClearFailed": { "placeholders": { "error": { "type": "String" } } }, + "@systemAiCacheClearFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "systemAiPullEmptyError": "Erst eine Modell-ID eintippen (z.B. gemma3:4b).", "systemAiPullFailedError": "Pull fehlgeschlagen: {error}", - "@systemAiPullFailedError": { "placeholders": { "error": { "type": "String" } } } + "@systemAiPullFailedError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "storeProvenanceTemporal": "temporal · {provider}", + "@storeProvenanceTemporal": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, + "storeSourceTemporal": "Temporal" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 6fce839..480a05d 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,9 +1,9 @@ { "@@locale": "en", - "appTitle": "F∆I Studio", - "@appTitle": { "description": "App-bar title in the OS task switcher." }, - + "@appTitle": { + "description": "App-bar title in the OS task switcher." + }, "navWelcome": "Welcome", "welcomeHeroTitle": "F∆I Platform", "welcomeHeroSubtitle": "Deterministic workflow engine for AI-assisted document processing in regulated environments.", @@ -32,7 +32,13 @@ "welcomeDocFlowsBlurb": "YAML basics, templating reference, the extract→summarize example.", "welcomeDocClose": "Close", "welcomeDocFailedToLoad": "Could not load documentation: {error}", - "@welcomeDocFailedToLoad": { "placeholders": { "error": { "type": "String" } } }, + "@welcomeDocFailedToLoad": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "welcomeChecklistHeader": "GETTING STARTED", "welcomeChecklistBody": "Four steps to a working hub. Live state — refresh after changing anything.", "welcomeChecklistAi": "Configure System AI", @@ -55,12 +61,10 @@ "navFlows": "Flows", "navAudit": "Audit", "navApprovals": "Approvals", - "connectionConnected": "connected", "connectionUnreachable": "unreachable", "connectionConnecting": "connecting…", "connectionStartHub": "Start hub", - "buttonCancel": "Cancel", "buttonSave": "Save", "buttonClose": "Close", @@ -81,8 +85,13 @@ "storeInstallableOnly": "Installable only", "storePillComingSoon": "Coming soon", "storeNotInstallableInline": "This module is on the roadmap (status: {status}). It has no installable bundle yet — follow the repository for updates.", - "@storeNotInstallableInline": { "placeholders": { "status": { "type": "String" } } }, - + "@storeNotInstallableInline": { + "placeholders": { + "status": { + "type": "String" + } + } + }, "mcpSuggestionDeepwikiDesc": "Public HTTPS — GitHub repo documentation search (AI-powered). No Node, no API key.", "mcpSuggestionSemgrepDesc": "Public HTTPS — security scanning for code vulnerabilities. No Node, no API key.", "mcpSuggestionFilesystemDesc": "Anthropic — read / write files in /tmp. Edit the path before saving.", @@ -95,12 +104,10 @@ "mcpSuggestionMemoryDesc": "Anthropic — persistent knowledge graph for an agent's memory.", "mcpSuggestionTimeDesc": "Anthropic — current time + timezone conversion.", "mcpServerEnLanguageBadge": "Server text in English — Studio shows it as supplied.", - "themePluginHeader": "Theme plugin", "themePluginNone": "Built-in (no plugin)", "themePluginHint": "Pick an installed studio.theme.* plugin to re-skin the whole app. Install one from the Store first.", "themePluginEmpty": "No theme plugins installed. Open the Store and pick one in the studio-plugin category.", - "settingsTitle": "Hub endpoint", "settingsHost": "Host", "settingsPort": "Port", @@ -120,16 +127,40 @@ "systemAiConfigure": "Configure…", "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.", "mcpServersCount": "{n} {n, plural, =1{server} other{servers}}", - "@mcpServersCount": { "placeholders": { "n": { "type": "int" } } }, + "@mcpServersCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "mcpRediscoverTooltip": "Re-run discovery", "mcpAddTooltip": "Add MCP server", "mcpRemoveTooltip": "Remove server", "mcpToolsCount": "{n} {n, plural, =1{tool} other{tools}}", - "@mcpToolsCount": { "placeholders": { "n": { "type": "int" } } }, + "@mcpToolsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nEndpointsCount": "{n} {n, plural, =1{endpoint} other{endpoints}}", - "@n8nEndpointsCount": { "placeholders": { "n": { "type": "int" } } }, + "@n8nEndpointsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nWorkflowsCount": "{n} {n, plural, =1{workflow} other{workflows}}", - "@n8nWorkflowsCount": { "placeholders": { "n": { "type": "int" } } }, + "@n8nWorkflowsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "n8nRediscoverTooltip": "Re-run discovery", "n8nAddTooltip": "Add n8n endpoint", "n8nRemoveTooltip": "Remove endpoint", @@ -155,16 +186,45 @@ "addN8nNotesLabel": "Notes (optional)", "addN8nAddButton": "Add + discover", "addedMcpToast": "Added MCP server \"{name}\".", - "@addedMcpToast": { "placeholders": { "name": { "type": "String" } } }, + "@addedMcpToast": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "addedN8nToast": "Added n8n endpoint \"{name}\".", - "@addedN8nToast": { "placeholders": { "name": { "type": "String" } } }, + "@addedN8nToast": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "addFailedToast": "Add failed: {error}", - "@addFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@addFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "removeFailedToast": "Remove failed: {error}", - "@removeFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@removeFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "refreshFailedToast": "Refresh failed: {error}", - "@refreshFailedToast": { "placeholders": { "error": { "type": "String" } } }, - + "@refreshFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "channelsHeader": "CHANNELS", "channelsActive": "active", "channelsRunning": "running", @@ -173,7 +233,6 @@ "channelsSwitch": "Make this the active channel", "channelsEnableAutostart": "Enable autostart at login", "channelsDisableAutostart": "Disable autostart", - "storeSearchHint": "Search modules — name, tagline, tag, capability…", "storeAskHint": "What do you need? Try \"a module that reads tabular data\" or just type a keyword.", "storeAskSubmit": "Search", @@ -187,7 +246,13 @@ "storeAskMatchPill": "match", "storeFilterLabel": "Filter", "storeFilterActiveCount": "{n} active", - "@storeFilterActiveCount": { "placeholders": { "n": { "type": "int" } } }, + "@storeFilterActiveCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "storeFilterReset": "Reset filters", "storeFilterApply": "Done", "storeFilterStatusGroup": "Status", @@ -217,7 +282,11 @@ "storeCategoryOrchestrator": "Orchestration", "storeNResults": "{n} result{n, plural, =1{} other{s}}", "@storeNResults": { - "placeholders": { "n": { "type": "int" } } + "placeholders": { + "n": { + "type": "int" + } + } }, "storeReloadTooltip": "Reload", "storeTodayBadge": "TODAY", @@ -226,38 +295,80 @@ "storePillInstalled": "installed", "storePillUpdate": "update", "storeUpdateButton": "Update to {version}", - "@storeUpdateButton": { "placeholders": { "version": { "type": "String" } } }, + "@storeUpdateButton": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "storeUpdateTooltip": "Installed {installed} — store has v{best}", "@storeUpdateTooltip": { "placeholders": { - "installed": { "type": "String" }, - "best": { "type": "String" } + "installed": { + "type": "String" + }, + "best": { + "type": "String" + } } }, "storeNoTagline": "(no tagline)", "storeUninstallTitle": "Uninstall module?", "storeUninstallBody": "Removes {name} from this hub. Flows that reference it will fail at the next run.", - "@storeUninstallBody": { "placeholders": { "name": { "type": "String" } } }, + "@storeUninstallBody": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "storeInstalledToast": "{name} v{version} installed.", "@storeInstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "storeInstallFailedToast": "Install failed: {error}", - "@storeInstallFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@storeInstallFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeUninstalledToast": "{name} v{version} uninstalled.", "@storeUninstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "storeUninstallFailedToast": "Uninstall failed: {error}", - "@storeUninstallFailedToast": { "placeholders": { "error": { "type": "String" } } }, + "@storeUninstallFailedToast": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeOpenBrowserFailed": "Could not open browser: {error}", - "@storeOpenBrowserFailed": { "placeholders": { "error": { "type": "String" } } }, + "@storeOpenBrowserFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "storeSectionTags": "Tags", "storeSectionRequiredCapabilities": "Required capabilities", "storeSectionRequiredHostServices": "Required host services", @@ -270,9 +381,21 @@ "storeInstallingButton": "Installing…", "storeNotInstallable": "Not installable", "storeNotInstallableTooltip": "Status \"{status}\" — install path not yet wired.", - "@storeNotInstallableTooltip": { "placeholders": { "status": { "type": "String" } } }, + "@storeNotInstallableTooltip": { + "placeholders": { + "status": { + "type": "String" + } + } + }, "storeInstallProgressTitle": "Installing {name}", - "@storeInstallProgressTitle": { "placeholders": { "name": { "type": "String" } } }, + "@storeInstallProgressTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "storeInstallProgressBody": "Fetching, verifying, unpacking…", "storeLoadDocs": "Load documentation", "storeDocsHint": "README rendered inline; uses the hub's registry token when needed.", @@ -282,7 +405,13 @@ "storeDocsErrorNoDocs": "No repository URL is recorded for this module.", "storeDocsErrorAuth": "The registry requires authentication to fetch this README. Set FAI_REGISTRY_TOKEN in the daemon's environment and restart the hub.", "storeDocsErrorNetwork": "Network error while fetching the README. {detail}", - "@storeDocsErrorNetwork": { "placeholders": { "detail": { "type": "String" } } }, + "@storeDocsErrorNetwork": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "storeDocsErrorParse": "README is not valid UTF-8.", "storeDocsErrorGeneric": "Could not load README.", "storeSourceLabel": "Source", @@ -292,9 +421,21 @@ "storeSourceN8n": "n8n", "storeProvenanceNative": "native", "storeProvenanceMcp": "mcp · {provider}", - "@storeProvenanceMcp": { "placeholders": { "provider": { "type": "String" } } }, + "@storeProvenanceMcp": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, "storeProvenanceN8n": "n8n · {provider}", - "@storeProvenanceN8n": { "placeholders": { "provider": { "type": "String" } } }, + "@storeProvenanceN8n": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, "storeRecommendedTitle": "Add a public source — one click", "storeRecommendedBody": "Curated MCP servers reachable over HTTPS. No subprocess, no API key, no Node. Federated capabilities appear in the store immediately.", "storeRecommendedAddTooltip": "Add and discover", @@ -304,22 +445,33 @@ "storeProviderAddedToast": "Added {name} — {n} federated {n, plural, =1{capability} other{capabilities}}.", "@storeProviderAddedToast": { "placeholders": { - "name": { "type": "String" }, - "n": { "type": "int" } + "name": { + "type": "String" + }, + "n": { + "type": "int" + } } }, "storeProviderAddedZeroToast": "{name} registered, but the server returned no capabilities yet. Open Settings → MCP Clients to retry discovery or check the server.", "@storeProviderAddedZeroToast": { - "placeholders": { "name": { "type": "String" } } + "placeholders": { + "name": { + "type": "String" + } + } }, "storeProviderAddFailed": "Could not add {name}: {error}", "@storeProviderAddFailed": { "placeholders": { - "name": { "type": "String" }, - "error": { "type": "String" } + "name": { + "type": "String" + }, + "error": { + "type": "String" + } } }, - "auditTitle": "Audit", "auditNoEvents": "No events yet", "auditNoEventsHint": "Run a flow to populate the audit stream.\nEvents appear here within seconds.", @@ -331,26 +483,60 @@ "auditClearedToast": "Cleared {n} events on channel \"{channel}\". Chain reseeded with marker.", "@auditClearedToast": { "placeholders": { - "n": { "type": "int" }, - "channel": { "type": "String" } + "n": { + "type": "int" + }, + "channel": { + "type": "String" + } } }, "auditClearFailed": "Clear failed: {detail}", - "@auditClearFailed": { "placeholders": { "detail": { "type": "String" } } }, + "@auditClearFailed": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "auditExplain": "Explain", "auditReask": "Re-ask", "auditAsking": "Asking…", "auditSystemAi": "SYSTEM AI", "auditCachedPill": "cached", "auditOriginalLatency": "orig {ms} ms", - "@auditOriginalLatency": { "placeholders": { "ms": { "type": "int" } } }, + "@auditOriginalLatency": { + "placeholders": { + "ms": { + "type": "int" + } + } + }, "auditLatency": "{ms} ms", - "@auditLatency": { "placeholders": { "ms": { "type": "int" } } }, + "@auditLatency": { + "placeholders": { + "ms": { + "type": "int" + } + } + }, "auditRegenerateTooltip": "Regenerate — skip cache, ask the model again", "auditLiveStatus": "live · polling 2s · {n} {n, plural, =1{event} other{events}}", - "@auditLiveStatus": { "placeholders": { "n": { "type": "int" } } }, + "@auditLiveStatus": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "auditDisconnected": "disconnected · {error}", - "@auditDisconnected": { "placeholders": { "error": { "type": "String" } } }, + "@auditDisconnected": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "auditHashChainVerified": "hash chain verified", "auditDetailHeader": "DETAIL", "auditAskingFull": "Asking the configured System AI…", @@ -358,14 +544,30 @@ "auditCachedTooltipKnown": "Served from the local cache. Originally generated on {at}{hits}.", "@auditCachedTooltipKnown": { "placeholders": { - "at": { "type": "String" }, - "hits": { "type": "String" } + "at": { + "type": "String" + }, + "hits": { + "type": "String" + } } }, "auditCachedTooltipUnknown": "Served from the local cache. Originally generated at unknown time{hits}.", - "@auditCachedTooltipUnknown": { "placeholders": { "hits": { "type": "String" } } }, + "@auditCachedTooltipUnknown": { + "placeholders": { + "hits": { + "type": "String" + } + } + }, "auditCachedTooltipHits": " · {n} hits", - "@auditCachedTooltipHits": { "placeholders": { "n": { "type": "int" } } }, + "@auditCachedTooltipHits": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "auditConfigureSystemAi": "Configure System AI in Settings (Cmd+,)", "auditClearDialogTitle": "Clear audit log?", "auditClearDialogBody": "Wipes every audit event on the active channel and seeds a fresh chain.reset marker carrying reviewer + reason. Refused on beta / production. Irreversible.", @@ -373,14 +575,19 @@ "auditClearReasonLabel": "Reason (recorded in chain.reset marker)", "auditClearReasonHelper": "Required — auditors will read this.", "auditClearLogButton": "Clear log", - "modulesTitle": "Modules", "modulesNoneTitle": "No modules yet", "modulesNoneHint": "Run `fai install ` or check ~/.fai/modules/.", "modulesReloadTooltip": "Reload", "modulesRecentActivity": "RECENT ACTIVITY", "modulesRecentActivityHint": "last {n} install/uninstall events from the audit log", - "@modulesRecentActivityHint": { "placeholders": { "n": { "type": "int" } } }, + "@modulesRecentActivityHint": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "modulesActivityInstalled": "installed", "modulesActivityUninstalled": "uninstalled", "modulesCapabilitiesLabel": "Capabilities", @@ -388,32 +595,57 @@ "modulesUninstallBody": "Removes {name} v{version} from this hub. Flows that reference it will fail at the next run. A `module.uninstalled` audit event is recorded.", "@modulesUninstallBody": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "modulesUninstalledToast": "Uninstalled {name} v{version}.", "@modulesUninstalledToast": { "placeholders": { - "name": { "type": "String" }, - "version": { "type": "String" } + "name": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "modulesUninstallFailed": "Uninstall failed: {error}", - "@modulesUninstallFailed": { "placeholders": { "error": { "type": "String" } } }, + "@modulesUninstallFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "modulesUninstalling": "Uninstalling…", "moduleSheetFailedToLoad": "Failed to load: {error}", - "@moduleSheetFailedToLoad": { "placeholders": { "error": { "type": "String" } } }, + "@moduleSheetFailedToLoad": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "moduleSheetCapabilities": "Capabilities", "moduleSheetPermissions": "Declared permissions", "moduleSheetNoPermissions": "(none — pure-computation module)", - "flowsTitle": "Flows", "flowsReloadTooltip": "Reload", "flowsNoneTitle": "No saved flows", "flowsNoneHint": "Save a flow with `fai admin flows save ` and it shows up here.", "flowsRunDialogTitle": "Run {name}", - "@flowsRunDialogTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsRunDialogTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "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.", "flowsLoadingDefinition": "Loading inputs…", "flowsDefinitionFailed": "Could not load flow definition", @@ -422,47 +654,89 @@ "flowsTypeBytesChange": "Change file", "flowsTypeBytesNoFile": "No file selected", "flowsTypeBytesSize": "{n} bytes", - "@flowsTypeBytesSize": { "placeholders": { "n": { "type": "int" } } }, + "@flowsTypeBytesSize": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "flowsRunErrorTitle": "Flow run failed", "flowsFileReadFailed": "Could not read \"{path}\": {error}", "@flowsFileReadFailed": { "placeholders": { - "path": { "type": "String" }, - "error": { "type": "String" } + "path": { + "type": "String" + }, + "error": { + "type": "String" + } } }, "flowsMissingModulesLabel": "Needs:", "flowsRunDisabledTooltip": "Install the missing modules first.", "flowsInstallAllButton": "Install all ({n})", - "@flowsInstallAllButton": { "placeholders": { "n": { "type": "int" } } }, + "@flowsInstallAllButton": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "flowsInstallPillTooltip": "Click to install", "flowsInstallDepsTitle": "Install dependencies", "flowsInstallDepsBody": "Walking through the missing modules in order. Existing installs are left alone.", "flowsInstallStatusPending": "Pending", "flowsInstallStatusInstalling": "Installing…", "flowsInstallStatusDone": "Installed v{version}", - "@flowsInstallStatusDone": { "placeholders": { "version": { "type": "String" } } }, + "@flowsInstallStatusDone": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "flowsInstallStatusFailed": "Failed", "flowsInstallStatusFailedDetail": "{error}", - "@flowsInstallStatusFailedDetail": { "placeholders": { "error": { "type": "String" } } }, + "@flowsInstallStatusFailedDetail": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "flowsInstallDepsAllDone": "All dependencies installed.", "flowsInstallDepsAnyFailed": "{ok} installed, {failed} failed.", "@flowsInstallDepsAnyFailed": { "placeholders": { - "ok": { "type": "int" }, - "failed": { "type": "int" } + "ok": { + "type": "int" + }, + "failed": { + "type": "int" + } } }, "flowsInstallAuthWallButton": "Add registry token", "flowsOpenInEditorTooltip": "Open the YAML file in your default editor", "flowsOpenInEditorFailed": "Could not open file: {error}", "@flowsOpenInEditorFailed": { - "placeholders": { "error": { "type": "String" } } + "placeholders": { + "error": { + "type": "String" + } + } }, "registryCredentialsHeader": "REGISTRY CREDENTIALS", "registryCredentialsBlurb": "Token used to download .fai modules from a registry behind a signin wall (Forgejo, GitHub-private). Stored at ~/.fai/registry-token, mode 0600. The FAI_REGISTRY_TOKEN env var still wins when set.", "registryTokenStatusConfigured": "Configured ({chars} chars)", - "@registryTokenStatusConfigured": { "placeholders": { "chars": { "type": "int" } } }, + "@registryTokenStatusConfigured": { + "placeholders": { + "chars": { + "type": "int" + } + } + }, "registryTokenStatusNotSet": "Not set", "registryTokenFieldLabel": "Token", "registryTokenFieldHint": "Paste your Forgejo or GitHub personal access token", @@ -473,7 +747,11 @@ "registryTokenClearedToast": "Registry token cleared.", "registryTokenSaveFailedToast": "Could not save: {error}", "@registryTokenSaveFailedToast": { - "placeholders": { "error": { "type": "String" } } + "placeholders": { + "error": { + "type": "String" + } + } }, "maintenanceHeader": "HUB MAINTENANCE", "maintenanceResetBlurb": "Wipe operator state and start over with a clean hub. Stops every running daemon, atomically backs ~/.fai/ up, then recreates it with the binary, channel state, MCP / n8n / system-AI config, and registry token preserved. Restore by moving the backup directory back.", @@ -503,41 +781,90 @@ "auditGroupOlder": "OLDER", "auditEventViewFlowRun": "View flow run", "auditFlowRunDialogTitle": "Flow run · {flow}", - "@auditFlowRunDialogTitle": { "placeholders": { "flow": { "type": "String" } } }, + "@auditFlowRunDialogTitle": { + "placeholders": { + "flow": { + "type": "String" + } + } + }, "auditFlowRunDialogSubtitle": "{n} {n, plural, =1{event} other{events}} for execution {execution}", "@auditFlowRunDialogSubtitle": { "placeholders": { - "n": { "type": "int" }, - "execution": { "type": "String" } + "n": { + "type": "int" + }, + "execution": { + "type": "String" + } } }, "approvalsSelectAll": "Select all", "approvalsClearSelection": "Clear", "approvalsBatchSelected": "{n} selected", - "@approvalsBatchSelected": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchSelected": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchApprove": "Approve all", "approvalsBatchReject": "Reject all", "approvalsBatchApproveDoneToast": "{n} approvals approved.", - "@approvalsBatchApproveDoneToast": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchApproveDoneToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchRejectDoneToast": "{n} approvals rejected.", - "@approvalsBatchRejectDoneToast": { "placeholders": { "n": { "type": "int" } } }, + "@approvalsBatchRejectDoneToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "approvalsBatchPartialFailure": "{ok} done, {failed} failed.", "@approvalsBatchPartialFailure": { "placeholders": { - "ok": { "type": "int" }, - "failed": { "type": "int" } + "ok": { + "type": "int" + }, + "failed": { + "type": "int" + } } }, "flowsRunButton": "Run", "flowsRunningTitle": "Running {name}", - "@flowsRunningTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsRunningTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsResultTitle": "{name} — result", - "@flowsResultTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsResultTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsErrorTitle": "{name} — failed", - "@flowsErrorTitle": { "placeholders": { "name": { "type": "String" } } }, + "@flowsErrorTitle": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "flowsRunning": "Flow running…", "flowsNoOutputs": "Flow completed with no declared outputs.", - "errGeneric": "Something went wrong.", "errInvalidArgument": "Invalid input.", "errInvalidArgumentHint": "Check the form values and try again.", @@ -561,13 +888,30 @@ "flowsOutputSaveAs": "Save as…", "flowsOutputSaveAsTitle": "Save flow output", "flowsOutputSavedAt": "Saved to {path}", - "@flowsOutputSavedAt": { "placeholders": { "path": { "type": "String" } } }, + "@flowsOutputSavedAt": { + "placeholders": { + "path": { + "type": "String" + } + } + }, "flowsOutputSaveFailed": "Save failed: {error}", - "@flowsOutputSaveFailed": { "placeholders": { "error": { "type": "String" } } }, + "@flowsOutputSaveFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "flowsOutputOpen": "Open", "flowsOutputOpenFailed": "Open failed: {error}", - "@flowsOutputOpenFailed": { "placeholders": { "error": { "type": "String" } } }, - + "@flowsOutputOpenFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsTitle": "Approvals", "approvalsTabPending": "Pending", "approvalsTabHistory": "History", @@ -586,21 +930,41 @@ "approvalsApprovedToast": "approved · {flow} › {step}", "@approvalsApprovedToast": { "placeholders": { - "flow": { "type": "String" }, - "step": { "type": "String" } + "flow": { + "type": "String" + }, + "step": { + "type": "String" + } } }, "approvalsRejectedToast": "rejected · {flow} › {step}", "@approvalsRejectedToast": { "placeholders": { - "flow": { "type": "String" }, - "step": { "type": "String" } + "flow": { + "type": "String" + }, + "step": { + "type": "String" + } } }, "approvalsApproveFailed": "approve failed: {error}", - "@approvalsApproveFailed": { "placeholders": { "error": { "type": "String" } } }, + "@approvalsApproveFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsRejectFailed": "reject failed: {error}", - "@approvalsRejectFailed": { "placeholders": { "error": { "type": "String" } } }, + "@approvalsRejectFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "approvalsHistoryEmpty": "No history yet", "approvalsHistoryEmptyHint": "Decided approvals (approved / rejected / expired) appear here.\nThe audit log keeps the full hash-chained record.", "approvalsDialogDecided": "decided", @@ -608,36 +972,67 @@ "approvalsDialogReason": "reason", "approvalsDialogPrompt": "PROMPT", "approvalsExpiresIn": "{minutes}m", - "@approvalsExpiresIn": { "placeholders": { "minutes": { "type": "int" } } }, + "@approvalsExpiresIn": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, "approvalsExpiresInHours": "{hours}h", - "@approvalsExpiresInHours": { "placeholders": { "hours": { "type": "int" } } }, - + "@approvalsExpiresInHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, "doctorTitle": "Doctor", "doctorSummaryModules": "Modules", "doctorSummaryApprovals": "Approvals", "doctorSummaryAudit": "Audit", "doctorSummaryServices": "Services", "doctorSummaryCapabilities": "{n} capabilities", - "@doctorSummaryCapabilities": { "placeholders": { "n": { "type": "int" } } }, + "@doctorSummaryCapabilities": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorSummaryPending": "pending", "doctorSummaryChain": "{verified}/{total} chain", "@doctorSummaryChain": { "placeholders": { - "verified": { "type": "int" }, - "total": { "type": "int" } + "verified": { + "type": "int" + }, + "total": { + "type": "int" + } } }, "doctorSummaryDeclared": "declared", "doctorModulesPanelSummary": "{n} modules · {m} capabilities", "@doctorModulesPanelSummary": { "placeholders": { - "n": { "type": "int" }, - "m": { "type": "int" } + "n": { + "type": "int" + }, + "m": { + "type": "int" + } } }, "doctorApprovalsNone": "No pending approvals", "doctorApprovalsCount": "{n, plural, =1{1 approval awaiting review} other{{n} approvals awaiting review}}", - "@doctorApprovalsCount": { "placeholders": { "n": { "type": "int" } } }, + "@doctorApprovalsCount": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorApprovalsAttentionPill": "attention", "doctorServicesEmpty": "No host services declared", "doctorServicesEmptyHint": "add to ~/.fai/config.yaml under services:", @@ -651,14 +1046,26 @@ "doctorDaemonControlSection": "Daemon control", "doctorChainIntact": "Hash chain intact", "doctorChainIntactDetail": "{n} events · prev_event_sha256 verified end-to-end", - "@doctorChainIntactDetail": { "placeholders": { "n": { "type": "int" } } }, + "@doctorChainIntactDetail": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "doctorChainTampered": "Tampering detected", "doctorChainTamperedDetail": "{verified} of {total} verified before mismatch at {id}", "@doctorChainTamperedDetail": { "placeholders": { - "verified": { "type": "int" }, - "total": { "type": "int" }, - "id": { "type": "String" } + "verified": { + "type": "int" + }, + "total": { + "type": "int" + }, + "id": { + "type": "String" + } } }, "doctorChainPillOk": "WORM-1", @@ -671,12 +1078,22 @@ "doctorRunningOn": "Running on {name}: {endpoint}", "@doctorRunningOn": { "placeholders": { - "name": { "type": "String" }, - "endpoint": { "type": "String" } + "name": { + "type": "String" + }, + "endpoint": { + "type": "String" + } } }, "doctorStoppedOn": "{name} daemon stopped", - "@doctorStoppedOn": { "placeholders": { "name": { "type": "String" } } }, + "@doctorStoppedOn": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "doctorStatusUnknown": "Daemon status: …", "doctorPillRunning": "running", "doctorPillStopped": "stopped", @@ -690,40 +1107,64 @@ "doctorPathPid": "PID file", "doctorPathsEmpty": "Daemon did not report file paths. Update the running hub via `fai daemon restart`.", "doctorOpenError": "Could not open: {detail}", - "@doctorOpenError": { "placeholders": { "detail": { "type": "String" } } }, + "@doctorOpenError": { + "placeholders": { + "detail": { + "type": "String" + } + } + }, "doctorUpdateAvailable": "Update available — {version}", - "@doctorUpdateAvailable": { "placeholders": { "version": { "type": "String" } } }, + "@doctorUpdateAvailable": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "doctorUpdateBody": "Channel {channel} now offers {version}. Apply via the button — Studio shells out to `fai update apply --channel {channel}`.", "@doctorUpdateBody": { "placeholders": { - "channel": { "type": "String" }, - "version": { "type": "String" } + "channel": { + "type": "String" + }, + "version": { + "type": "String" + } } }, "doctorUpdateUnreachable": "Release host unreachable", "doctorUpdateUnreachableBody": "Could not contact the release feed for {channel}.", - "@doctorUpdateUnreachableBody": { "placeholders": { "channel": { "type": "String" } } }, + "@doctorUpdateUnreachableBody": { + "placeholders": { + "channel": { + "type": "String" + } + } + }, "doctorReleaseNotes": "notes: {url}", - "@doctorReleaseNotes": { "placeholders": { "url": { "type": "String" } } }, + "@doctorReleaseNotes": { + "placeholders": { + "url": { + "type": "String" + } + } + }, "doctorPillNew": "new", "doctorPillOffline": "offline", "doctorApplyUpdate": "Apply update", "doctorApplying": "Applying…", "doctorApplyDone": "Update applied. Restart Studio to see the new daemon version.", - "mcpHeader": "MCP CLIENTS", "mcpHint": "External MCP servers federate their tools as `mcp..` capabilities. Configure once, see them in the Store.", "mcpEmpty": "No MCP servers configured. Click + to add one.", "n8nHeader": "N8N ENDPOINTS", "n8nHint": "Active n8n workflows surface as `n8n..` capabilities. Configure once, see them in the Store.", "n8nEmpty": "No n8n endpoints configured. Click + to add one.", - "hubUnreachable": "Hub unreachable", "hubUnreachableHint": "Start the hub with `fai serve`.", - "languageEnglish": "English", "languageGerman": "Deutsch", - "searchHint": "Jump anywhere — modules, store, flows, pages…", "searchIndexing": "Indexing…", "searchNoMatches": "No matches.", @@ -736,17 +1177,40 @@ "searchGroupFlows": "Flows", "searchSettingsLabel": "Settings", "searchPageHint": "page · ⌘{n}", - "@searchPageHint": { "placeholders": { "n": { "type": "int" } } }, + "@searchPageHint": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "searchSettingsHint": "hub endpoint, channels, system AI · ⌘;", "searchInstalledModuleHint": "installed module · v{version}", - "@searchInstalledModuleHint": { "placeholders": { "version": { "type": "String" } } }, + "@searchInstalledModuleHint": { + "placeholders": { + "version": { + "type": "String" + } + } + }, "searchStoreUncategorized": "uncategorized", "searchStoreHintWithTagline": "store · {tagline}", - "@searchStoreHintWithTagline": { "placeholders": { "tagline": { "type": "String" } } }, + "@searchStoreHintWithTagline": { + "placeholders": { + "tagline": { + "type": "String" + } + } + }, "searchStoreHintWithCategory": "store · {category}", - "@searchStoreHintWithCategory": { "placeholders": { "category": { "type": "String" } } }, + "@searchStoreHintWithCategory": { + "placeholders": { + "category": { + "type": "String" + } + } + }, "searchSavedFlowHint": "saved flow", - "systemAiTitle": "System AI", "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.", "systemAiProviderLabel": "Provider", @@ -754,7 +1218,13 @@ "systemAiApiKeyRequired": "API key env var (required)", "systemAiApiKeyOptional": "API key env var (optional)", "systemAiApiKeyDisclaimer": "Studio never reads or stores the key value — only its env-var name. The hub reads `${name}` at request time.", - "@systemAiApiKeyDisclaimer": { "placeholders": { "name": { "type": "String" } } }, + "@systemAiApiKeyDisclaimer": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "systemAiTestConnection": "Test connection", "systemAiTesting": "Testing…", "systemAiSave": "Save", @@ -768,7 +1238,13 @@ "systemAiConnectionOk": "Connection ok", "systemAiConnectionFailed": "Connection failed", "systemAiReplyPrefix": "Reply: {text}", - "@systemAiReplyPrefix": { "placeholders": { "text": { "type": "String" } } }, + "@systemAiReplyPrefix": { + "placeholders": { + "text": { + "type": "String" + } + } + }, "systemAiModelLabel": "Model (required)", "systemAiModelHintFallback": "model identifier the provider expects", "systemAiModelHelperBase": "Required: pick from the list (Refresh) or type one.", @@ -777,7 +1253,13 @@ "systemAiPull": "Pull", "systemAiPulling": "Pulling…", "systemAiCouldNotListModels": "Could not list models: {error}", - "@systemAiCouldNotListModels": { "placeholders": { "error": { "type": "String" } } }, + "@systemAiCouldNotListModels": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "systemAiNoModelsOllama": "No models on the Ollama server yet. Type one above and click Pull.", "systemAiNoModelsGeneric": "Provider returned no models.", "systemAiSuitabilityRecommended": "recommended", @@ -787,23 +1269,74 @@ "systemAiSuitabilityHuge": "huge — likely too slow on a laptop", "systemAiSuitabilityUnknown": "size unknown", "systemAiHwDetected": "Detected: {summary}", - "@systemAiHwDetected": { "placeholders": { "summary": { "type": "String" } } }, + "@systemAiHwDetected": { + "placeholders": { + "summary": { + "type": "String" + } + } + }, "systemAiHwReviewed": " · curation reviewed {date}", - "@systemAiHwReviewed": { "placeholders": { "date": { "type": "String" } } }, + "@systemAiHwReviewed": { + "placeholders": { + "date": { + "type": "String" + } + } + }, "systemAiLegendRecommended": "recommended for this hardware{tier}", - "@systemAiLegendRecommended": { "placeholders": { "tier": { "type": "String" } } }, + "@systemAiLegendRecommended": { + "placeholders": { + "tier": { + "type": "String" + } + } + }, "systemAiLegendBalanced": "balanced (4-8B)", "systemAiLegendSmallLarge": "small <3B / large 9-15B / above hardware", "systemAiLegendHuge": "huge >15B", "systemAiLegendUnknown": "size unknown", "systemAiCacheRow": "Cache: {n} cached {n, plural, =1{explanation} other{explanations}}. Identical prompts hit the cache; switching model or privacy mode flushes automatically.", - "@systemAiCacheRow": { "placeholders": { "n": { "type": "int" } } }, + "@systemAiCacheRow": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "systemAiCacheClear": "Clear", "systemAiCacheClearedToast": "Cleared {n} cached System-AI explanations.", - "@systemAiCacheClearedToast": { "placeholders": { "n": { "type": "int" } } }, + "@systemAiCacheClearedToast": { + "placeholders": { + "n": { + "type": "int" + } + } + }, "systemAiCacheClearFailed": "Cache clear failed: {error}", - "@systemAiCacheClearFailed": { "placeholders": { "error": { "type": "String" } } }, + "@systemAiCacheClearFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, "systemAiPullEmptyError": "Type a model id (e.g. gemma3:4b) first.", "systemAiPullFailedError": "Pull failed: {error}", - "@systemAiPullFailedError": { "placeholders": { "error": { "type": "String" } } } + "@systemAiPullFailedError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "storeProvenanceTemporal": "temporal · {provider}", + "@storeProvenanceTemporal": { + "placeholders": { + "provider": { + "type": "String" + } + } + }, + "storeSourceTemporal": "Temporal" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 3a9abc9..ce982f4 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3565,6 +3565,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Pull failed: {error}'** String systemAiPullFailedError(String error); + + /// No description provided for @storeProvenanceTemporal. + /// + /// In en, this message translates to: + /// **'temporal · {provider}'** + String storeProvenanceTemporal(String provider); + + /// No description provided for @storeSourceTemporal. + /// + /// In en, this message translates to: + /// **'Temporal'** + String get storeSourceTemporal; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 4ed5cbe..2fdbbdc 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2084,4 +2084,12 @@ class AppLocalizationsDe extends AppLocalizations { String systemAiPullFailedError(String error) { return 'Pull fehlgeschlagen: $error'; } + + @override + String storeProvenanceTemporal(String provider) { + return 'temporal · $provider'; + } + + @override + String get storeSourceTemporal => 'Temporal'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 3a59368..38c2b46 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2090,4 +2090,12 @@ class AppLocalizationsEn extends AppLocalizations { String systemAiPullFailedError(String error) { return 'Pull failed: $error'; } + + @override + String storeProvenanceTemporal(String provider) { + return 'temporal · $provider'; + } + + @override + String get storeSourceTemporal => 'Temporal'; } diff --git a/lib/pages/store.dart b/lib/pages/store.dart index 210338b..d28352d 100644 --- a/lib/pages/store.dart +++ b/lib/pages/store.dart @@ -1030,6 +1030,7 @@ class _FilterDialogState extends State<_FilterDialog> { (value: 'native', label: l.storeSourceNative), (value: 'mcp', label: l.storeSourceMcp), (value: 'n8n', label: l.storeSourceN8n), + (value: 'temporal', label: l.storeSourceTemporal), ], _source, (v) => setState(() => _source = v), @@ -3355,6 +3356,13 @@ class _ProvenancePill extends StatelessWidget { monospace: true, icon: Icons.account_tree_outlined, ); + case 'temporal': + return FaiPill( + label: l.storeProvenanceTemporal(item.provider), + tone: FaiPillTone.accent, + monospace: true, + icon: Icons.timer_outlined, + ); default: // Native is the default: no badge needed. Keeps the // card visually quiet — only foreign code (mcp / n8n)