diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml new file mode 100644 index 00000000..30f3999e --- /dev/null +++ b/.github/workflows/dependabot-automerge.yml @@ -0,0 +1,40 @@ +# QNBS-v3: proposed during the deployment-surface/OpenRouter audit (2026-07-28) — a 31-day commit +# gap let 20 Dependabot PRs stack up (see AUDIT.md / TODO.md). Auto-merging PATCH-only bumps once +# CI is green cuts that latency without touching the judgment calls minor/major bumps deserve. The +# existing dev-tooling/tauri-deps groups and the 7-day release cooldown (.npmrc minimum-release-age) +# are unchanged — this only adds a merge step gated on CI + semver-patch. +name: Dependabot Auto-Merge + +on: + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + auto-merge: + name: Auto-merge patch-level Dependabot PRs + # QNBS-v3: github.actor is the last actor to trigger the event, not the immutable PR author — + # spoofable (confused-deputy risk) for gating a contents:write/pull-requests:write job. + # github.event.pull_request.user.login is set at PR creation and can't be manipulated this way. + if: github.event.pull_request.user.login == 'dependabot[bot]' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + # QNBS-v3: patch-only, on purpose — minor/major bumps (or any bump outside npm/cargo/ + # github-actions, e.g. a group update mixing semver levels) still need a human look. + - name: Enable auto-merge for semver-patch updates + if: steps.metadata.outputs.update-type == 'version-update:semver-patch' + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/locales/ar/settings.json b/locales/ar/settings.json index 6de202c7..b1d78832 100644 --- a/locales/ar/settings.json +++ b/locales/ar/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "تصدير JSON", - "dashboard.backup.hint": "صدّر مشروعك، أو استورد نسخة احتياطية، أو افتح إعدادات النسخ الاحتياطي الكاملة.", - "dashboard.backup.importJson": "استيراد JSON", - "dashboard.backup.latestSnapshot": "أحدث لقطة: {{name}} ‏({{date}})", - "dashboard.backup.openSettings": "إعدادات النسخ الاحتياطي", - "dashboard.backup.title": "النسخ الاحتياطي والاستعادة", - "dashboard.backup.unnamedSnapshot": "لقطة بلا اسم", - "error.boundary.retryAnnouncement": "أُعيد تحميل {{view}} بعد خطأ.", - "error.boundary.retryAnnouncementGeneric": "أُعيد تحميل العرض بعد خطأ.", - "sceneboard.minimap.ariaLabel": "خريطة مصغّرة للوحة الحبكة", "settings.about.description": "شريكك الإبداعي المدعوم بالذكاء الاصطناعي للكتابة.", "settings.about.githubDescription": "اعرض الكود المصدري، وأبلغ عن المشكلات، وساهم.", "settings.about.githubLabel": "مفتوح المصدر على GitHub", diff --git a/locales/de/settings.json b/locales/de/settings.json index 8f9799ed..54ba181a 100644 --- a/locales/de/settings.json +++ b/locales/de/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "JSON exportieren", - "dashboard.backup.hint": "Projekt exportieren, Backup importieren oder Einstellungen öffnen.", - "dashboard.backup.importJson": "JSON importieren", - "dashboard.backup.latestSnapshot": "Letzter Snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup-Einstellungen", - "dashboard.backup.title": "Backup & Wiederherstellung", - "dashboard.backup.unnamedSnapshot": "Unbenannter Snapshot", - "error.boundary.retryAnnouncement": "{{view}} nach einem Fehler neu geladen.", - "error.boundary.retryAnnouncementGeneric": "Ansicht nach einem Fehler neu geladen.", - "sceneboard.minimap.ariaLabel": "Plot-Board-Minikarte", "settings.about.description": "Ihr KI-gestützter kreativer Partner für das Schreiben.", "settings.about.githubDescription": "Quellcode ansehen, Fehler melden und mitmachen.", "settings.about.githubLabel": "Open-Source auf GitHub", diff --git a/locales/el/settings.json b/locales/el/settings.json index c7db449c..508922ec 100644 --- a/locales/el/settings.json +++ b/locales/el/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Εξαγωγή JSON", - "dashboard.backup.hint": "Εξαγωγή your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Εισαγωγή JSON", - "dashboard.backup.latestSnapshot": "Τελευταίο στιγμιότυπο: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Ρυθμίσεις δημιουργίας αντιγράφων ασφαλείας", - "dashboard.backup.title": "Δημιουργία αντιγράφων ασφαλείας και επαναφορά", - "dashboard.backup.unnamedSnapshot": "Στιγμιότυπο χωρίς όνομα", - "error.boundary.retryAnnouncement": "Το {{view}} φορτώθηκε ξανά μετά από σφάλμα.", - "error.boundary.retryAnnouncementGeneric": "Η προβολή φορτώθηκε ξανά μετά από σφάλμα.", - "sceneboard.minimap.ariaLabel": "Μίνι χάρτης σανίδας οικοπέδου", "settings.about.description": "Ο δημιουργικός συνεργάτης σας με τεχνητή νοημοσύνη για τη γραφή.", "settings.about.githubDescription": "Δείτε τον πηγαίο κώδικα, αναφέρετε προβλήματα και συνεισφέρετε.", "settings.about.githubLabel": "Ανοιχτού κώδικα στο GitHub", diff --git a/locales/en/settings.json b/locales/en/settings.json index d1f8f829..2df90e31 100644 --- a/locales/en/settings.json +++ b/locales/en/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Export JSON", - "dashboard.backup.hint": "Export your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Import JSON", - "dashboard.backup.latestSnapshot": "Latest snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup settings", - "dashboard.backup.title": "Backup & restore", - "dashboard.backup.unnamedSnapshot": "Unnamed snapshot", - "error.boundary.retryAnnouncement": "{{view}} reloaded after an error.", - "error.boundary.retryAnnouncementGeneric": "View reloaded after an error.", - "sceneboard.minimap.ariaLabel": "Plot board mini-map", "settings.about.description": "Your AI-powered creative partner for writing.", "settings.about.githubDescription": "View source code, report issues, and contribute.", "settings.about.githubLabel": "Open-source on GitHub", @@ -248,16 +238,16 @@ "settings.ai.temperature.creative": "2 – Creative", "settings.ai.temperature.precise": "0 – Precise", "settings.ai.testConnection": "Test connection", - "settings.ai.testError.noApiKey": "No {{provider}} API key set", - "settings.ai.testError.httpError": "HTTP {{status}}", - "settings.ai.testError.timeout": "Connection timed out ({{url}})", - "settings.ai.testError.unreachable": "Not reachable ({{url}})", - "settings.ai.testError.pluginUnavailable": "Local server networking is unavailable: the desktop HTTP plugin failed to load.", - "settings.ai.testError.desktopRequired": "Ollama and local OpenAI-compatible servers are only available in the desktop app. Browsers block direct connections from web pages to localhost (CORS and Private Network Access).", "settings.ai.testError.backendProxyRequired": "Claude requires a backend proxy (CORS restriction)", + "settings.ai.testError.desktopRequired": "Ollama and local OpenAI-compatible servers are only available in the desktop app. Browsers block direct connections from web pages to localhost (CORS and Private Network Access).", + "settings.ai.testError.httpError": "HTTP {{status}}", + "settings.ai.testError.noApiKey": "No {{provider}} API key set", "settings.ai.testError.noWebgpu": "WebGPU unavailable in this browser — WebLLM needs WebGPU (try Chrome/Edge or enable flags).", - "settings.ai.testError.unknownProvider": "Unknown provider", + "settings.ai.testError.pluginUnavailable": "Local server networking is unavailable: the desktop HTTP plugin failed to load.", + "settings.ai.testError.timeout": "Connection timed out ({{url}})", "settings.ai.testError.unexpected": "An unexpected error occurred. Please try again.", + "settings.ai.testError.unknownProvider": "Unknown provider", + "settings.ai.testError.unreachable": "Not reachable ({{url}})", "settings.ai.title": "AI Configuration", "settings.ai.transformers.hint": "Runs any Xenova-compatible HuggingFace model locally via WebAssembly or WebGPU.", "settings.ai.transformers.modelId": "Model ID (HuggingFace)", diff --git a/locales/es/dashboard.json b/locales/es/dashboard.json index 619cd6fe..f82fbaf5 100644 --- a/locales/es/dashboard.json +++ b/locales/es/dashboard.json @@ -10,13 +10,13 @@ "dashboard.authorInsights.timelineClear": "Sin avisos desde los metadatos de escena.", "dashboard.authorInsights.timelineWarnBadge": "{{count}} avisos — revisa fechas/duraciones en el tablero.", "dashboard.authorInsights.title": "Información de pipeline del autor", - "dashboard.backup.exportJson": "JSON exportieren", - "dashboard.backup.hint": "Projekt exportieren, Backup importieren oder Einstellungen öffnen.", - "dashboard.backup.importJson": "JSON importieren", - "dashboard.backup.latestSnapshot": "Letzter Snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup-Einstellungen", - "dashboard.backup.title": "Backup & Wiederherstellung", - "dashboard.backup.unnamedSnapshot": "Unbenannter Snapshot", + "dashboard.backup.exportJson": "Exportar JSON", + "dashboard.backup.hint": "Exporta tu proyecto, importa una copia de seguridad o abre la configuración completa de copias de seguridad.", + "dashboard.backup.importJson": "Importar JSON", + "dashboard.backup.latestSnapshot": "Última instantánea: {{name}} ({{date}})", + "dashboard.backup.openSettings": "Configuración de copias de seguridad", + "dashboard.backup.title": "Copia de seguridad y restauración", + "dashboard.backup.unnamedSnapshot": "Instantánea sin nombre", "dashboard.composition.avgPerScene": "Media / escena", "dashboard.composition.empty": "Añade escenas en el Manuscrito para ver su composición.", "dashboard.composition.readingTime": "Tiempo de lectura", diff --git a/locales/es/settings.json b/locales/es/settings.json index ebcb17b8..4db6a854 100644 --- a/locales/es/settings.json +++ b/locales/es/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Export JSON", - "dashboard.backup.hint": "Export your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Import JSON", - "dashboard.backup.latestSnapshot": "Latest snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup settings", - "dashboard.backup.title": "Backup & restore", - "dashboard.backup.unnamedSnapshot": "Unnamed snapshot", - "error.boundary.retryAnnouncement": "{{view}} reloaded after an error.", - "error.boundary.retryAnnouncementGeneric": "View reloaded after an error.", - "sceneboard.minimap.ariaLabel": "Plot board mini-map", "settings.about.description": "Tu compañero creativo de escritura con IA.", "settings.about.githubDescription": "Ver el código fuente, reportar errores y contribuir.", "settings.about.githubLabel": "Código abierto en GitHub", diff --git a/locales/eu/settings.json b/locales/eu/settings.json index 875d914d..17ae6dd9 100644 --- a/locales/eu/settings.json +++ b/locales/eu/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Esportatu JSON", - "dashboard.backup.hint": "Esportatu zure proiektua, inportatu babeskopia bat edo ireki babeskopien ezarpen osoak.", - "dashboard.backup.importJson": "Inportatu JSON", - "dashboard.backup.latestSnapshot": "Azken argazkia: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Babeskopia-ezarpenak", - "dashboard.backup.title": "Babeskopia egin eta leheneratu", - "dashboard.backup.unnamedSnapshot": "Izenik gabeko argazkia", - "error.boundary.retryAnnouncement": "{{view}} berriro kargatu da errore baten ondoren.", - "error.boundary.retryAnnouncementGeneric": "Ikusi birkargatu da errore baten ondoren.", - "sceneboard.minimap.ariaLabel": "Orube-taula txiki-mapa", "settings.about.description": "Idazketarako AI-k bultzatutako sormen-kidea.", "settings.about.githubDescription": "Ikusi iturburu-kodea, jakinarazi arazoen berri eta eman ekarpenak.", "settings.about.githubLabel": "Kode irekia GitHub-en", diff --git a/locales/fa/settings.json b/locales/fa/settings.json index 1129ac17..5a9cab56 100644 --- a/locales/fa/settings.json +++ b/locales/fa/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "صادرات JSON", - "dashboard.backup.hint": "پروژه خود را صادر کنید، یک نسخه پشتیبان وارد کنید یا تنظیمات پشتیبان کامل را باز کنید.", - "dashboard.backup.importJson": "JSON را وارد کنید", - "dashboard.backup.latestSnapshot": "آخرین عکس فوری: {{name}} ({{date}})", - "dashboard.backup.openSettings": "تنظیمات پشتیبان گیری", - "dashboard.backup.title": "پشتیبان گیری و بازیابی", - "dashboard.backup.unnamedSnapshot": "عکس فوری بدون نام", - "error.boundary.retryAnnouncement": "{{view}} پس از یک خطا دوباره بارگیری شد.", - "error.boundary.retryAnnouncementGeneric": "مشاهده پس از خطا بارگیری مجدد شد.", - "sceneboard.minimap.ariaLabel": "مینی نقشه تخته پلات", "settings.about.description": "شریک خلاق شما با هوش مصنوعی برای نوشتن.", "settings.about.githubDescription": "مشاهده کد منبع، گزارش مشکلات، و مشارکت.", "settings.about.githubLabel": "منبع باز در GitHub", diff --git a/locales/fi/settings.json b/locales/fi/settings.json index 1f4e2c01..8a5f4e5b 100644 --- a/locales/fi/settings.json +++ b/locales/fi/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Vie JSON", - "dashboard.backup.hint": "Vie projektisi, tuo varmuuskopio tai avaa täydelliset varmuuskopiointiasetukset.", - "dashboard.backup.importJson": "Tuo JSON", - "dashboard.backup.latestSnapshot": "Viimeisin tilannekuva: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Varmuuskopiointiasetukset", - "dashboard.backup.title": "Varmuuskopiointi ja palautus", - "dashboard.backup.unnamedSnapshot": "Nimetön tilannekuva", - "error.boundary.retryAnnouncement": "{{view}} ladattu uudelleen virheen jälkeen.", - "error.boundary.retryAnnouncementGeneric": "Näkymä ladattu uudelleen virheen jälkeen.", - "sceneboard.minimap.ariaLabel": "Tonttitaulun minikartta", "settings.about.description": "Tekoälyllä toimiva luova kumppanisi kirjoittamiseen.", "settings.about.githubDescription": "Tarkastele lähdekoodia, ilmoita ongelmista ja osallistu.", "settings.about.githubLabel": "Avoin lähdekoodi GitHubissa", diff --git a/locales/fr/settings.json b/locales/fr/settings.json index 84f78cb6..4892b12f 100644 --- a/locales/fr/settings.json +++ b/locales/fr/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Export JSON", - "dashboard.backup.hint": "Export your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Import JSON", - "dashboard.backup.latestSnapshot": "Latest snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup settings", - "dashboard.backup.title": "Backup & restore", - "dashboard.backup.unnamedSnapshot": "Unnamed snapshot", - "error.boundary.retryAnnouncement": "{{view}} reloaded after an error.", - "error.boundary.retryAnnouncementGeneric": "View reloaded after an error.", - "sceneboard.minimap.ariaLabel": "Plot board mini-map", "settings.about.description": "Votre partenaire créatif pour l'écriture, propulsé par l'IA.", "settings.about.githubDescription": "Voir le code source, signaler des bugs et contribuer.", "settings.about.githubLabel": "Open-source sur GitHub", diff --git a/locales/he/settings.json b/locales/he/settings.json index 049a0938..03836944 100644 --- a/locales/he/settings.json +++ b/locales/he/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "ייצוא JSON", - "dashboard.backup.hint": "ייצאו את הפרויקט, ייבאו גיבוי, או פתחו את הגדרות הגיבוי המלאות.", - "dashboard.backup.importJson": "ייבוא JSON", - "dashboard.backup.latestSnapshot": "תמונת המצב האחרונה: {{name}} ‏({{date}})", - "dashboard.backup.openSettings": "הגדרות גיבוי", - "dashboard.backup.title": "גיבוי ושחזור", - "dashboard.backup.unnamedSnapshot": "תמונת מצב ללא שם", - "error.boundary.retryAnnouncement": "{{view}} נטענה מחדש לאחר שגיאה.", - "error.boundary.retryAnnouncementGeneric": "התצוגה נטענה מחדש לאחר שגיאה.", - "sceneboard.minimap.ariaLabel": "מפה ממוזערת של לוח העלילה", "settings.about.description": "השותף היצירתי המופעל ב‑AI שלכם לכתיבה.", "settings.about.githubDescription": "צפו בקוד המקור, דווחו על בעיות ותרמו.", "settings.about.githubLabel": "קוד פתוח ב‑GitHub", diff --git a/locales/hu/settings.json b/locales/hu/settings.json index 980f6f37..94afe2f4 100644 --- a/locales/hu/settings.json +++ b/locales/hu/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "JSON exportálása", - "dashboard.backup.hint": "Exportálja projektjét, importáljon biztonsági másolatot, vagy nyissa meg a teljes biztonsági mentési beállításokat.", - "dashboard.backup.importJson": "JSON importálása", - "dashboard.backup.latestSnapshot": "Legutóbbi pillanatkép: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Biztonsági mentés beállításai", - "dashboard.backup.title": "Biztonsági mentés és visszaállítás", - "dashboard.backup.unnamedSnapshot": "Névtelen pillanatkép", - "error.boundary.retryAnnouncement": "{{view}} hiba után újratöltve.", - "error.boundary.retryAnnouncementGeneric": "A nézet újratöltve hiba után.", - "sceneboard.minimap.ariaLabel": "Telektábla mini-térkép", "settings.about.description": "Az Ön mesterséges intelligenciájú kreatív partnere az íráshoz.", "settings.about.githubDescription": "Tekintse meg a forráskódot, jelentse a problémákat és járuljon hozzá.", "settings.about.githubLabel": "Nyílt forráskód a GitHubon", diff --git a/locales/is/settings.json b/locales/is/settings.json index f612e7a8..b53f975f 100644 --- a/locales/is/settings.json +++ b/locales/is/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Flytja út JSON", - "dashboard.backup.hint": "Flyttu út verkefnið þitt, fluttu inn afrit eða opnaðu allar öryggisafritunarstillingar.", - "dashboard.backup.importJson": "Flytja inn JSON", - "dashboard.backup.latestSnapshot": "Nýjasta skyndimynd: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Stillingar fyrir öryggisafrit", - "dashboard.backup.title": "Afrita og endurheimta", - "dashboard.backup.unnamedSnapshot": "Ónefnd skyndimynd", - "error.boundary.retryAnnouncement": "{{view}} endurhlaðinn eftir villu.", - "error.boundary.retryAnnouncementGeneric": "Skoða endurhlaðinn eftir villu.", - "sceneboard.minimap.ariaLabel": "Lítið kort af teikniborði", "settings.about.description": "Skapandi félagi þinn með gervigreind til að skrifa.", "settings.about.githubDescription": "Skoðaðu frumkóðann, tilkynntu vandamál og leggðu þitt af mörkum.", "settings.about.githubLabel": "Opinn uppspretta á GitHub", diff --git a/locales/it/settings.json b/locales/it/settings.json index 2d8dd439..073c1423 100644 --- a/locales/it/settings.json +++ b/locales/it/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Export JSON", - "dashboard.backup.hint": "Export your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Import JSON", - "dashboard.backup.latestSnapshot": "Latest snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup settings", - "dashboard.backup.title": "Backup & restore", - "dashboard.backup.unnamedSnapshot": "Unnamed snapshot", - "error.boundary.retryAnnouncement": "{{view}} reloaded after an error.", - "error.boundary.retryAnnouncementGeneric": "View reloaded after an error.", - "sceneboard.minimap.ariaLabel": "Plot board mini-map", "settings.about.description": "Il tuo partner creativo per la scrittura, potenziato dall'IA.", "settings.about.githubDescription": "Visualizza il codice sorgente, segnala problemi e contribuisci.", "settings.about.githubLabel": "Open-source su GitHub", diff --git a/locales/ja/settings.json b/locales/ja/settings.json index f3a93c03..ff8aafbd 100644 --- a/locales/ja/settings.json +++ b/locales/ja/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "エクスポート JSON", - "dashboard.backup.hint": "エクスポート your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "JSONをインポートする", - "dashboard.backup.latestSnapshot": "最新のスナップショット: {{name}} ({{date}})", - "dashboard.backup.openSettings": "バックアップ設定", - "dashboard.backup.title": "バックアップと復元", - "dashboard.backup.unnamedSnapshot": "名前のないスナップショット", - "error.boundary.retryAnnouncement": "エラー後に {{view}} がリロードされました。", - "error.boundary.retryAnnouncementGeneric": "エラー後にビューがリロードされました。", - "sceneboard.minimap.ariaLabel": "プロットボードのミニマップ", "settings.about.description": "AI を活用したライティングのためのクリエイティブ パートナー。", "settings.about.githubDescription": "ソース コードを表示し、問題を報告し、貢献します。", "settings.about.githubLabel": "GitHub 上のオープンソース", diff --git a/locales/ko/settings.json b/locales/ko/settings.json index 6eefe41d..a7b019f6 100644 --- a/locales/ko/settings.json +++ b/locales/ko/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "JSON 내보내기", - "dashboard.backup.hint": "프로젝트를 내보내거나, 백업을 가져오거나, 전체 백업 설정을 엽니다.", - "dashboard.backup.importJson": "JSON 가져오기", - "dashboard.backup.latestSnapshot": "최신 스냅샷: {{name}} ({{date}})", - "dashboard.backup.openSettings": "백업 설정", - "dashboard.backup.title": "백업 및 복원", - "dashboard.backup.unnamedSnapshot": "이름이 지정되지 않은 스냅샷", - "error.boundary.retryAnnouncement": "{{view}} 오류가 발생한 후 다시 로드되었습니다.", - "error.boundary.retryAnnouncementGeneric": "오류가 발생한 후 다시 로드된 보기입니다.", - "sceneboard.minimap.ariaLabel": "플롯 보드 미니맵", "settings.about.description": "글쓰기를 위한 AI 기반 크리에이티브 파트너.", "settings.about.githubDescription": "소스 코드를 보고, 문제를 보고하고, 기여하세요.", "settings.about.githubLabel": "GitHub의 오픈 소스", diff --git a/locales/pt/settings.json b/locales/pt/settings.json index 9b1d7642..ae1d3c90 100644 --- a/locales/pt/settings.json +++ b/locales/pt/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Exportar JSON", - "dashboard.backup.hint": "Exportar your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Importar JSON", - "dashboard.backup.latestSnapshot": "Instantâneo mais recente: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Configurações de backup", - "dashboard.backup.title": "Backup e restauração", - "dashboard.backup.unnamedSnapshot": "Instantâneo sem nome", - "error.boundary.retryAnnouncement": "{{view}} recarregado após um erro.", - "error.boundary.retryAnnouncementGeneric": "Visualização recarregada após um erro.", - "sceneboard.minimap.ariaLabel": "Minimapa do quadro de plotagem", "settings.about.description": "Your IA-powered creative partner for writing.", "settings.about.githubDescription": "Visualize o código-fonte, relate problemas e contribua.", "settings.about.githubLabel": "Código aberto no GitHub", diff --git a/locales/ru/settings.json b/locales/ru/settings.json index 9e7c47d7..9d8fde22 100644 --- a/locales/ru/settings.json +++ b/locales/ru/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Экспорт JSON", - "dashboard.backup.hint": "Экспортируйте свой проект, импортируйте резервную копию или откройте полные настройки резервного копирования.", - "dashboard.backup.importJson": "Импортировать JSON", - "dashboard.backup.latestSnapshot": "Последний снимок: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Настройки резервного копирования", - "dashboard.backup.title": "Резервное копирование и восстановление", - "dashboard.backup.unnamedSnapshot": "Безымянный снимок", - "error.boundary.retryAnnouncement": "{{view}} перезагружается после ошибки.", - "error.boundary.retryAnnouncementGeneric": "Просмотр перезагружен после ошибки.", - "sceneboard.minimap.ariaLabel": "Мини-карта планшета", "settings.about.description": "Ваш творческий партнер на базе искусственного интеллекта для написания статей.", "settings.about.githubDescription": "Просматривайте исходный код, сообщайте о проблемах и вносите свой вклад.", "settings.about.githubLabel": "Открытый исходный код на GitHub", diff --git a/locales/sv/settings.json b/locales/sv/settings.json index 519951cb..3dd3c2de 100644 --- a/locales/sv/settings.json +++ b/locales/sv/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "Exportera JSON", - "dashboard.backup.hint": "Exportera ditt projekt, importera en säkerhetskopia eller öppna inställningar för fullständig säkerhetskopiering.", - "dashboard.backup.importJson": "Importera JSON", - "dashboard.backup.latestSnapshot": "Senaste ögonblicksbilden: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Säkerhetskopieringsinställningar", - "dashboard.backup.title": "Säkerhetskopiera och återställa", - "dashboard.backup.unnamedSnapshot": "Namnlös ögonblicksbild", - "error.boundary.retryAnnouncement": "{{view}} laddades om efter ett fel.", - "error.boundary.retryAnnouncementGeneric": "Vyn har laddats om efter ett fel.", - "sceneboard.minimap.ariaLabel": "Rittavla minikarta", "settings.about.description": "Din AI-drivna kreativa partner för skrivande.", "settings.about.githubDescription": "Visa källkod, rapportera problem och bidra.", "settings.about.githubLabel": "Öppen källkod på GitHub", diff --git a/locales/zh/settings.json b/locales/zh/settings.json index 1b62b778..13e90189 100644 --- a/locales/zh/settings.json +++ b/locales/zh/settings.json @@ -1,14 +1,4 @@ { - "dashboard.backup.exportJson": "导出 JSON", - "dashboard.backup.hint": "导出 your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "导入 JSON", - "dashboard.backup.latestSnapshot": "最新快照:{{name}}({{date}})", - "dashboard.backup.openSettings": "备份设置", - "dashboard.backup.title": "备份与恢复", - "dashboard.backup.unnamedSnapshot": "未命名快照", - "error.boundary.retryAnnouncement": "{{view}} 发生错误后重新加载。", - "error.boundary.retryAnnouncementGeneric": "出现错误后重新加载视图。", - "sceneboard.minimap.ariaLabel": "绘图板小地图", "settings.about.description": "您的人工智能写作创意合作伙伴。", "settings.about.githubDescription": "查看源代码、报告问题并做出贡献。", "settings.about.githubLabel": "在 GitHub 上开源", diff --git a/public/locales/el/bundle.json b/public/locales/el/bundle.json index ea30e576..6dd91d27 100644 --- a/public/locales/el/bundle.json +++ b/public/locales/el/bundle.json @@ -885,7 +885,7 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} προειδοποιήσεις — βελτιώστε τις ημερομηνίες/διάρκειες των σκηνών στον πίνακα σκηνής.", "dashboard.authorInsights.title": "Insights για τη διοχέτευση του συγγραφέα", "dashboard.backup.exportJson": "Εξαγωγή JSON", - "dashboard.backup.hint": "Εξαγωγή your project, import a backup, or open full backup settings.", + "dashboard.backup.hint": "Εξάγετε το έργο σας, εισαγάγετε ένα αντίγραφο ασφαλείας ή ανοίξτε τις ρυθμίσεις πλήρους αντιγράφου ασφαλείας.", "dashboard.backup.importJson": "Εισαγωγή JSON", "dashboard.backup.latestSnapshot": "Τελευταίο στιγμιότυπο: {{name}} ({{date}})", "dashboard.backup.openSettings": "Ρυθμίσεις δημιουργίας αντιγράφων ασφαλείας", diff --git a/public/locales/en/bundle.json b/public/locales/en/bundle.json index fc4e3d4e..18818fa2 100644 --- a/public/locales/en/bundle.json +++ b/public/locales/en/bundle.json @@ -1856,16 +1856,16 @@ "settings.ai.temperature.creative": "2 – Creative", "settings.ai.temperature.precise": "0 – Precise", "settings.ai.testConnection": "Test connection", - "settings.ai.testError.noApiKey": "No {{provider}} API key set", - "settings.ai.testError.httpError": "HTTP {{status}}", - "settings.ai.testError.timeout": "Connection timed out ({{url}})", - "settings.ai.testError.unreachable": "Not reachable ({{url}})", - "settings.ai.testError.pluginUnavailable": "Local server networking is unavailable: the desktop HTTP plugin failed to load.", - "settings.ai.testError.desktopRequired": "Ollama and local OpenAI-compatible servers are only available in the desktop app. Browsers block direct connections from web pages to localhost (CORS and Private Network Access).", "settings.ai.testError.backendProxyRequired": "Claude requires a backend proxy (CORS restriction)", + "settings.ai.testError.desktopRequired": "Ollama and local OpenAI-compatible servers are only available in the desktop app. Browsers block direct connections from web pages to localhost (CORS and Private Network Access).", + "settings.ai.testError.httpError": "HTTP {{status}}", + "settings.ai.testError.noApiKey": "No {{provider}} API key set", "settings.ai.testError.noWebgpu": "WebGPU unavailable in this browser — WebLLM needs WebGPU (try Chrome/Edge or enable flags).", - "settings.ai.testError.unknownProvider": "Unknown provider", + "settings.ai.testError.pluginUnavailable": "Local server networking is unavailable: the desktop HTTP plugin failed to load.", + "settings.ai.testError.timeout": "Connection timed out ({{url}})", "settings.ai.testError.unexpected": "An unexpected error occurred. Please try again.", + "settings.ai.testError.unknownProvider": "Unknown provider", + "settings.ai.testError.unreachable": "Not reachable ({{url}})", "settings.ai.title": "AI Configuration", "settings.ai.transformers.hint": "Runs any Xenova-compatible HuggingFace model locally via WebAssembly or WebGPU.", "settings.ai.transformers.modelId": "Model ID (HuggingFace)", diff --git a/public/locales/es/bundle.json b/public/locales/es/bundle.json index 9bc1fd03..485327f2 100644 --- a/public/locales/es/bundle.json +++ b/public/locales/es/bundle.json @@ -886,13 +886,13 @@ "dashboard.authorInsights.timelineClear": "Sin avisos desde los metadatos de escena.", "dashboard.authorInsights.timelineWarnBadge": "{{count}} avisos — revisa fechas/duraciones en el tablero.", "dashboard.authorInsights.title": "Información de pipeline del autor", - "dashboard.backup.exportJson": "Export JSON", - "dashboard.backup.hint": "Export your project, import a backup, or open full backup settings.", - "dashboard.backup.importJson": "Import JSON", - "dashboard.backup.latestSnapshot": "Latest snapshot: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Backup settings", - "dashboard.backup.title": "Backup & restore", - "dashboard.backup.unnamedSnapshot": "Unnamed snapshot", + "dashboard.backup.exportJson": "Exportar JSON", + "dashboard.backup.hint": "Exporta tu proyecto, importa una copia de seguridad o abre la configuración completa de copias de seguridad.", + "dashboard.backup.importJson": "Importar JSON", + "dashboard.backup.latestSnapshot": "Última instantánea: {{name}} ({{date}})", + "dashboard.backup.openSettings": "Configuración de copias de seguridad", + "dashboard.backup.title": "Copia de seguridad y restauración", + "dashboard.backup.unnamedSnapshot": "Instantánea sin nombre", "dashboard.composition.avgPerScene": "Media / escena", "dashboard.composition.empty": "Añade escenas en el Manuscrito para ver su composición.", "dashboard.composition.readingTime": "Tiempo de lectura", diff --git a/public/locales/eu/bundle.json b/public/locales/eu/bundle.json index 4429ecdc..9bfb5856 100644 --- a/public/locales/eu/bundle.json +++ b/public/locales/eu/bundle.json @@ -885,11 +885,11 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} abisu — zehaztu eszenen datak/iraupenak Eszena-taulan.", "dashboard.authorInsights.title": "Egilearen prozesuaren ikuspegiak", "dashboard.backup.exportJson": "Esportatu JSON", - "dashboard.backup.hint": "Esportatu zure proiektua, inportatu babeskopia bat edo ireki babeskopien ezarpen osoak.", + "dashboard.backup.hint": "Esportatu zure proiektua, inportatu babeskopia bat, edo ireki babeskopia-ezarpen osoak.", "dashboard.backup.importJson": "Inportatu JSON", "dashboard.backup.latestSnapshot": "Azken argazkia: {{name}} ({{date}})", "dashboard.backup.openSettings": "Babeskopia-ezarpenak", - "dashboard.backup.title": "Babeskopia egin eta leheneratu", + "dashboard.backup.title": "Babeskopia eta leheneratzea", "dashboard.backup.unnamedSnapshot": "Izenik gabeko argazkia", "dashboard.composition.avgPerScene": "Batez best. / eszena", "dashboard.composition.empty": "Gehitu eszenak Eskuizkribuan haren osaera ikusteko.", diff --git a/public/locales/fa/bundle.json b/public/locales/fa/bundle.json index d12b9128..ce2e417d 100644 --- a/public/locales/fa/bundle.json +++ b/public/locales/fa/bundle.json @@ -885,12 +885,12 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} هشدار — تاریخ‌ها/مدت‌های صحنه را در تخته‌صحنه دقیق‌تر کنید.", "dashboard.authorInsights.title": "بینش‌های خط‌لوله نویسنده", "dashboard.backup.exportJson": "صادرات JSON", - "dashboard.backup.hint": "پروژه خود را صادر کنید، یک نسخه پشتیبان وارد کنید یا تنظیمات پشتیبان کامل را باز کنید.", - "dashboard.backup.importJson": "JSON را وارد کنید", - "dashboard.backup.latestSnapshot": "آخرین عکس فوری: {{name}} ({{date}})", - "dashboard.backup.openSettings": "تنظیمات پشتیبان گیری", - "dashboard.backup.title": "پشتیبان گیری و بازیابی", - "dashboard.backup.unnamedSnapshot": "عکس فوری بدون نام", + "dashboard.backup.hint": "پروژه خود را خروجی بگیرید، یک پشتیبان وارد کنید، یا تنظیمات کامل پشتیبان‌گیری را باز کنید.", + "dashboard.backup.importJson": "ورودی JSON", + "dashboard.backup.latestSnapshot": "آخرین تصویر لحظه‌ای: {{name}} ({{date}})", + "dashboard.backup.openSettings": "تنظیمات پشتیبان‌گیری", + "dashboard.backup.title": "پشتیبان‌گیری و بازیابی", + "dashboard.backup.unnamedSnapshot": "تصویر لحظه‌ای بی‌نام", "dashboard.composition.avgPerScene": "میانگین / صحنه", "dashboard.composition.empty": "برای دیدن ترکیب دست‌نوشته، در آن صحنه اضافه کنید.", "dashboard.composition.readingTime": "زمان مطالعه", diff --git a/public/locales/fi/bundle.json b/public/locales/fi/bundle.json index 306b5ac7..1468c5c3 100644 --- a/public/locales/fi/bundle.json +++ b/public/locales/fi/bundle.json @@ -885,12 +885,12 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} varoitusta — tarkenna kohtausten päiviä/kestoja Kohtaustaulussa.", "dashboard.authorInsights.title": "Kirjailijan putken oivallukset", "dashboard.backup.exportJson": "Vie JSON", - "dashboard.backup.hint": "Vie projektisi, tuo varmuuskopio tai avaa täydelliset varmuuskopiointiasetukset.", + "dashboard.backup.hint": "Vie projektisi, tuo varmuuskopio tai avaa täydet varmuuskopiointiasetukset.", "dashboard.backup.importJson": "Tuo JSON", - "dashboard.backup.latestSnapshot": "Viimeisin tilannekuva: {{name}} ({{date}})", + "dashboard.backup.latestSnapshot": "Viimeisin tilannevedos: {{name}} ({{date}})", "dashboard.backup.openSettings": "Varmuuskopiointiasetukset", "dashboard.backup.title": "Varmuuskopiointi ja palautus", - "dashboard.backup.unnamedSnapshot": "Nimetön tilannekuva", + "dashboard.backup.unnamedSnapshot": "Nimetön tilannevedos", "dashboard.composition.avgPerScene": "Keskim. / kohtaus", "dashboard.composition.empty": "Lisää kohtauksia Käsikirjoitukseen nähdäksesi sen koostumuksen.", "dashboard.composition.readingTime": "Lukuaika", diff --git a/public/locales/hu/bundle.json b/public/locales/hu/bundle.json index dada5bb6..109146ac 100644 --- a/public/locales/hu/bundle.json +++ b/public/locales/hu/bundle.json @@ -885,10 +885,10 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} figyelmeztetés — pontosítsd a jelenetek dátumait/időtartamait a Jelenettáblán.", "dashboard.authorInsights.title": "Szerzői folyamat – betekintések", "dashboard.backup.exportJson": "JSON exportálása", - "dashboard.backup.hint": "Exportálja projektjét, importáljon biztonsági másolatot, vagy nyissa meg a teljes biztonsági mentési beállításokat.", + "dashboard.backup.hint": "Exportáld a projektedet, importálj egy biztonsági mentést, vagy nyisd meg a teljes mentési beállításokat.", "dashboard.backup.importJson": "JSON importálása", "dashboard.backup.latestSnapshot": "Legutóbbi pillanatkép: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Biztonsági mentés beállításai", + "dashboard.backup.openSettings": "Mentési beállítások", "dashboard.backup.title": "Biztonsági mentés és visszaállítás", "dashboard.backup.unnamedSnapshot": "Névtelen pillanatkép", "dashboard.composition.avgPerScene": "Átl. / jelenet", diff --git a/public/locales/is/bundle.json b/public/locales/is/bundle.json index d94ffd56..0c6888a8 100644 --- a/public/locales/is/bundle.json +++ b/public/locales/is/bundle.json @@ -885,11 +885,11 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} viðvaranir — fínstilltu dagsetningar/lengdir senu á Senuborðinu.", "dashboard.authorInsights.title": "Innsýn í höfundarferlið", "dashboard.backup.exportJson": "Flytja út JSON", - "dashboard.backup.hint": "Flyttu út verkefnið þitt, fluttu inn afrit eða opnaðu allar öryggisafritunarstillingar.", + "dashboard.backup.hint": "Flyttu út verkefnið þitt, flyttu inn afrit, eða opnaðu fullar afritunarstillingar.", "dashboard.backup.importJson": "Flytja inn JSON", "dashboard.backup.latestSnapshot": "Nýjasta skyndimynd: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Stillingar fyrir öryggisafrit", - "dashboard.backup.title": "Afrita og endurheimta", + "dashboard.backup.openSettings": "Afritunarstillingar", + "dashboard.backup.title": "Afritun og endurheimt", "dashboard.backup.unnamedSnapshot": "Ónefnd skyndimynd", "dashboard.composition.avgPerScene": "Meðaltal / senu", "dashboard.composition.empty": "Bættu senum við í Handritið til að sjá samsetningu þess.", diff --git a/public/locales/ja/bundle.json b/public/locales/ja/bundle.json index 2d8ba81f..1e13e4ee 100644 --- a/public/locales/ja/bundle.json +++ b/public/locales/ja/bundle.json @@ -884,8 +884,8 @@ "dashboard.authorInsights.timelineClear": "シーンのメタデータからのタイムライン警告はありません。", "dashboard.authorInsights.timelineWarnBadge": "{{count}} 件の警告 — シーン ボードでシーンの日付/期間を調整します。", "dashboard.authorInsights.title": "著者パイプラインの洞察", - "dashboard.backup.exportJson": "エクスポート JSON", - "dashboard.backup.hint": "エクスポート your project, import a backup, or open full backup settings.", + "dashboard.backup.exportJson": "JSONのエクスポート", + "dashboard.backup.hint": "プロジェクトをエクスポートするか、バックアップをインポートするか、完全バックアップ設定を開きます。", "dashboard.backup.importJson": "JSONをインポートする", "dashboard.backup.latestSnapshot": "最新のスナップショット: {{name}} ({{date}})", "dashboard.backup.openSettings": "バックアップ設定", diff --git a/public/locales/pt/bundle.json b/public/locales/pt/bundle.json index ffff2afd..215efa72 100644 --- a/public/locales/pt/bundle.json +++ b/public/locales/pt/bundle.json @@ -885,7 +885,7 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} avisos — refine as datas/durações das cenas no Scene Board.", "dashboard.authorInsights.title": "Insights do pipeline do autor", "dashboard.backup.exportJson": "Exportar JSON", - "dashboard.backup.hint": "Exportar your project, import a backup, or open full backup settings.", + "dashboard.backup.hint": "Exporte seu projeto, importe um backup ou abra as configurações de backup completo.", "dashboard.backup.importJson": "Importar JSON", "dashboard.backup.latestSnapshot": "Instantâneo mais recente: {{name}} ({{date}})", "dashboard.backup.openSettings": "Configurações de backup", diff --git a/public/locales/sv/bundle.json b/public/locales/sv/bundle.json index bf4e2b06..6c542cb6 100644 --- a/public/locales/sv/bundle.json +++ b/public/locales/sv/bundle.json @@ -885,11 +885,11 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} varningar — finjustera scenernas datum/varaktigheter på Scentavlan.", "dashboard.authorInsights.title": "Insikter om författarpipelinen", "dashboard.backup.exportJson": "Exportera JSON", - "dashboard.backup.hint": "Exportera ditt projekt, importera en säkerhetskopia eller öppna inställningar för fullständig säkerhetskopiering.", + "dashboard.backup.hint": "Exportera ditt projekt, importera en säkerhetskopia eller öppna fullständiga inställningar för säkerhetskopiering.", "dashboard.backup.importJson": "Importera JSON", - "dashboard.backup.latestSnapshot": "Senaste ögonblicksbilden: {{name}} ({{date}})", - "dashboard.backup.openSettings": "Säkerhetskopieringsinställningar", - "dashboard.backup.title": "Säkerhetskopiera och återställa", + "dashboard.backup.latestSnapshot": "Senaste ögonblicksbild: {{name}} ({{date}})", + "dashboard.backup.openSettings": "Inställningar för säkerhetskopiering", + "dashboard.backup.title": "Säkerhetskopiering och återställning", "dashboard.backup.unnamedSnapshot": "Namnlös ögonblicksbild", "dashboard.composition.avgPerScene": "Snitt / scen", "dashboard.composition.empty": "Lägg till scener i manuskriptet för att se dess sammansättning.", diff --git a/public/locales/zh/bundle.json b/public/locales/zh/bundle.json index e0e54f7a..aa09be0f 100644 --- a/public/locales/zh/bundle.json +++ b/public/locales/zh/bundle.json @@ -885,7 +885,7 @@ "dashboard.authorInsights.timelineWarnBadge": "{{count}} 条警告 — 在场景板上优化场景日期/持续时间。", "dashboard.authorInsights.title": "作者管道见解", "dashboard.backup.exportJson": "导出 JSON", - "dashboard.backup.hint": "导出 your project, import a backup, or open full backup settings.", + "dashboard.backup.hint": "导出项目、导入备份或打开完整备份设置。", "dashboard.backup.importJson": "导入 JSON", "dashboard.backup.latestSnapshot": "最新快照:{{name}}({{date}})", "dashboard.backup.openSettings": "备份设置", diff --git a/scripts/audit-feature-parity.ts b/scripts/audit-feature-parity.ts index 768fd2f2..8af3d079 100644 --- a/scripts/audit-feature-parity.ts +++ b/scripts/audit-feature-parity.ts @@ -134,6 +134,27 @@ function extractSectionFlags(sectionSrc: string, catalogSrc: string): Set !hidden.has(flag))); } +// QNBS-v3: a flag hidden from FeatureFlagsSection.tsx can still have a real toggle elsewhere (e.g. enableIdbAtRestEncryption → PrivacySection.tsx) — derived from each catalog entry's own gateLocations. +function extractDedicatedUiFlags(catalogSrc: string): Set { + const dedicated = new Set(); + const flagKeyMatches = [...catalogSrc.matchAll(/flagKey:\s*['"`](enable\w+)['"`]/g)]; + for (let i = 0; i < flagKeyMatches.length; i++) { + const match = flagKeyMatches[i]; + const flag = match?.[1]; + if (!flag || match.index === undefined) continue; + const nextIndex = flagKeyMatches[i + 1]?.index ?? catalogSrc.length; + const entrySrc = catalogSrc.slice(match.index, nextIndex); + const gateLocationsInner = entrySrc.match(/gateLocations:\s*\[([\s\S]*?)\n\s*\],/)?.[1]; + if ( + gateLocationsInner && + /components\/settings\/(?!FeatureFlagsSection\.tsx)[\w-]+\.tsx/.test(gateLocationsInner) + ) { + dedicated.add(flag); + } + } + return dedicated; +} + // --------------------------------------------------------------------------- // Step 5: Extract flags from useSettingsView.ts switch // --------------------------------------------------------------------------- @@ -165,6 +186,8 @@ const sliceFlags = extractFlagsFromSlice(sliceSrc); const defaultFlags = extractDefaultsFromSlice(sliceSrc); const localeFlags = extractLocaleFlags(localeSrc); const sectionFlags = extractSectionFlags(sectionSrc, catalogSrc); +// QNBS-v3: tracked separately from sectionFlags so a dedicated-elsewhere toggle doesn't get conflated with the generic catalog-driven list. +const dedicatedUiFlags = extractDedicatedUiFlags(catalogSrc); const handlerFlags = extractHandlerFlags(hookSrc); let errors = 0; @@ -178,6 +201,8 @@ const rows: Array<{ inDefaults: boolean; inLocale: boolean; inSection: boolean; + // QNBS-v3: kept alongside inSection so the report can distinguish "no UI" from "UI elsewhere". + hasDedicatedUi: boolean; inHandler: boolean; hasRuntime: boolean; }> = []; @@ -186,9 +211,11 @@ for (const flag of sliceFlags) { const inDefaults = defaultFlags.has(flag); const inLocale = localeFlags.has(flag); const inSection = sectionFlags.has(flag); + // QNBS-v3: computed independently of inSection — a flag can be both "not in the generic section" and "has a dedicated toggle" at once. + const hasDedicatedUi = dedicatedUiFlags.has(flag); const inHandler = handlerFlags.has(flag); const hasRuntime = hasRuntimeConsumption(flag); - rows.push({ flag, inDefaults, inLocale, inSection, inHandler, hasRuntime }); + rows.push({ flag, inDefaults, inLocale, inSection, hasDedicatedUi, inHandler, hasRuntime }); } // Print table header @@ -207,13 +234,15 @@ console.log('─'.repeat(90)); for (const row of rows) { const check = (v: boolean) => (v ? green('✅') : red('❌')); const runtimeCheck = row.hasRuntime ? green('✅') : yellow('⚠️ '); + // QNBS-v3: a dedicated toggle elsewhere (e.g. PrivacySection.tsx) is real UI, not a flat "no toggle" ❌ — shown distinctly as ◆. + const sectionCheck = row.inSection ? green('✅') : row.hasDedicatedUi ? green('◆') : red('❌'); const flagLabel = row.flag.padEnd(34); const line = [ flagLabel, check(row.inDefaults).padEnd(18), check(row.inLocale).padEnd(16), - check(row.inSection).padEnd(18), + sectionCheck.padEnd(18), check(row.inHandler).padEnd(18), runtimeCheck, ].join(''); @@ -223,7 +252,7 @@ for (const row of rows) { // Count issues if (!row.inDefaults) errors++; if (!row.inLocale) errors++; - if (!row.inSection) warnings++; // warning — dev-only flags may intentionally skip UI + if (!row.inSection && !row.hasDedicatedUi) warnings++; // QNBS-v3: only warns when there's truly no toggle anywhere — dev-only flags may intentionally skip UI if (!row.inSection && row.inHandler) errors++; // handler without UI toggle is dead code if (row.inSection && !row.inHandler) errors++; // UI toggle with no handler = critical bug if (!row.hasRuntime) warnings++; // ghost flag @@ -280,10 +309,20 @@ if (ghostFlags.length > 0) { console.log(); } -// Warnings: flags in section but not in handler -const noUiToggle = rows.filter((r) => !r.inSection); +// QNBS-v3: reported separately from noUiToggle below — these flags DO have real UI, just not in the generic section, so they shouldn't read as a gap. +const dedicatedUiOnly = rows.filter((r) => !r.inSection && r.hasDedicatedUi); +if (dedicatedUiOnly.length > 0) { + console.log(green('INFO — Flags with a dedicated UI toggle outside FeatureFlagsSection.tsx:')); + for (const r of dedicatedUiOnly) { + console.log(green(` • ${r.flag} — see its gateLocations entry in featureCatalog.ts`)); + } + console.log(); +} + +// Warnings: flags with no UI toggle anywhere (neither the generic section nor a dedicated one) +const noUiToggle = rows.filter((r) => !r.inSection && !r.hasDedicatedUi); if (noUiToggle.length > 0) { - console.log(yellow('INFO — Flags with no UI toggle (Settings cannot change them):')); + console.log(yellow('WARNING — Flags with no UI toggle anywhere (Settings cannot change them):')); for (const r of noUiToggle) { console.log(yellow(` • ${r.flag}`)); }