From a9d72ee4cf5406b4caf51ddeb0765525da0d9cb1 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:46:29 +0200 Subject: [PATCH 01/14] docs: ADR-0012 + LOCAL-AI root-cause & desktop local-server guide (#266) Root-cause analysis for Ollama/LM Studio/vLLM discovery on Tauri and the PWA CORS noise: WebView fetch to localhost is cross-origin (CORS/PNA), CSP was never the blocker. Decision: route local-server HTTP through the Tauri HTTP plugin; PWA stays strictly desktop-only. Help articles updated (Tauri desktop, provider FAQ). --- docs/LOCAL-AI.md | 39 ++++++- ...12-local-server-connectivity-tauri-http.md | 102 ++++++++++++++++++ locales/en/help.json | 4 +- 3 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 docs/adr/0012-local-server-connectivity-tauri-http.md diff --git a/docs/LOCAL-AI.md b/docs/LOCAL-AI.md index 633c0709..39be09a0 100644 --- a/docs/LOCAL-AI.md +++ b/docs/LOCAL-AI.md @@ -93,7 +93,41 @@ fallback. In **Local** and **Eco** modes, only the on-device chain is used. removes them. Different browsers do not share downloads. - **Desktop (Tauri):** the same WebGPU/WASM runtimes apply; downloads live in the app's WebView storage. For server-grade local models, point the **Ollama** provider at a local - server instead (Settings → AI Models → AI → Advanced). + server instead (Settings → AI Models → AI → Advanced) — see the next section. + +--- + +## Ollama / LM Studio / vLLM servers (desktop only) + +For server-grade local models, WorldScript Studio talks to a **local inference server** over +HTTP instead of running the model in the WebView: + +| Server | Default URL | Notes | +|---|---|---| +| **Ollama** | `http://localhost:11434` | `ollama serve`; models via the Models list or `ollama pull` | +| **LM Studio** | `http://localhost:1234` | Enable the local server in LM Studio (Developer tab) | +| **vLLM** | `http://localhost:8000` | Any OpenAI-compatible `/v1` server works | + +Setup: **Settings → AI Models → AI → Advanced**, pick the **Ollama** provider, choose a preset +(or enter a custom base URL), then press **Scan common local ports**. Every endpoint gets a +live status badge (reachable / no response / timeout / HTTP error); a reachable server offers a +one-click **Use this URL** action. + +### Why this only works in the desktop app + +- **Desktop (Tauri):** all local-server traffic goes through the **Tauri HTTP plugin** (native + Rust networking), not the WebView's `fetch`. Native requests are not subject to browser CORS or + Private-Network-Access rules, so Ollama/LM Studio answer directly — **no `OLLAMA_ORIGINS` + configuration needed**. The Tauri capability scope is pinned to `localhost`/`127.0.0.1` + (`src-tauri/capabilities/default.json`); the CSP already lists the three well-known ports. +- **Web (PWA):** browsers treat `http://localhost:*` as cross-origin **and** as a private-network + target. Without server-side CORS headers (`OLLAMA_ORIGINS=…` including your PWA origin) every + request is blocked — this is a browser security boundary, not a bug. The PWA therefore shows a + banner with a link to the desktop download instead of probing your machine, and never fires + automatic localhost requests (no CORS noise in the console). + +See [ADR 0012](adr/0012-local-server-connectivity-tauri-http.md) for the full root-cause analysis +(issue #266). --- @@ -106,6 +140,9 @@ fallback. In **Local** and **Eco** modes, only the on-device chain is used. | "Another WorldScript tab holds the local inference lock" | Multi-tab GPU contention | Close other WorldScript tabs (only one tab loads the GPU model). | | Very slow generation | Low-end device / CPU fallback | Pick a smaller model or use **Eco** mode. | | Storage estimate unavailable | Browser without StorageManager | Informational only; downloads still work. | +| Ollama/LM Studio not detected (desktop) | Server not running, or custom port | Run `ollama serve` / start the LM Studio server; press **Scan common local ports**; check the base URL. | +| CORS errors mention `localhost:11434` (browser) | Ollama selected inside the PWA | Expected browser boundary — use the desktop app for local servers (see banner in Settings → AI). | +| Scan shows **timeout** | Server busy loading a model or firewall interference | Retry after the model finishes loading; check OS firewall for localhost. | The **Last local run: N tokens/sec** line under the fallback chain reflects the throughput of your most recent on-device generation — a quick way to compare models on your hardware. diff --git a/docs/adr/0012-local-server-connectivity-tauri-http.md b/docs/adr/0012-local-server-connectivity-tauri-http.md new file mode 100644 index 00000000..13accefa --- /dev/null +++ b/docs/adr/0012-local-server-connectivity-tauri-http.md @@ -0,0 +1,102 @@ +# ADR 0012 — Local AI server connectivity: route localhost HTTP through the Tauri HTTP plugin (web stays fetch) + +- **Status:** Accepted +- **Date:** 2026-07-25 +- **Deciders:** Maintainer + Kimi Code +- **Context tags:** ai, ollama, lm-studio, tauri, cors, csp, private-network-access +- **Fixes:** [#266](https://github.com/qnbs/WorldScript-Studio/issues/266) · extends [ADR 0004](0004-csp-connect-src-byok-tradeoff.md) + +## Context + +WorldScript Studio can use server-grade local models through the **Ollama** provider and can scan +for local OpenAI-compatible servers (Ollama `:11434`, LM Studio `:1234`, vLLM `:8000`). Two failure +modes were reported in #266: + +1. **Desktop build (.deb / Tauri) does not see Ollama or LM Studio even though both are running.** +2. **The installed PWA logs loud CORS errors against `localhost:11434` even when `OLLAMA_ORIGINS` + is configured.** + +### Root cause analysis + +- `services/ollamaService.ts` (`testOllamaConnection`, `listOllamaModels`, `streamOllama`, + `pullOllamaModel`) and `scanLocalOpenAiCompatibleEndpoints()` (`services/aiProviderService.ts`) + all used the **browser `fetch`** — including inside the Tauri WebView. +- The Tauri WebView origin is `http://tauri.localhost` (Linux/Windows) resp. `tauri://localhost` + (macOS). Requests to `http://localhost:11434` etc. are therefore **cross-origin**. Ollama sends + **no `Access-Control-Allow-Origin` header** unless the server is started with `OLLAMA_ORIGINS` + covering the WebView origin — the WebView then blocks the response (CORS). LM Studio and vLLM + behave similarly depending on their own CORS configuration. WebView2/WKWebView additionally apply + Private-Network-Access / mixed-content style restrictions to `localhost` targets. +- The Tauri CSP (`src-tauri/tauri.conf.json` `connect-src`) already listed all three ports for + `localhost` and `127.0.0.1`. **CSP was never the blocker — CORS was.** CSP can only *forbid* a + connection; it can never *permit* a cross-origin read that the server does not allow. +- In the PWA, `AiProviderCard`'s auto-effect fired `listOllamaModels()` **directly** (bypassing the + desktop-only guard inside `testAIConnection`) whenever the Ollama provider was selected. Each + settings visit produced CORS preflight failures in the console. `OLLAMA_ORIGINS` can silence this + only if the PWA origin is explicitly listed — but the browser path is desktop-only by policy + anyway, so auto-probing localhost from the PWA is simply wrong. +- `@tauri-apps/plugin-http` (JS) and `tauri-plugin-http` (Rust) were **already dependencies**, and + the `http:default` capability was already granted — but nothing on the Ollama path used them. The + plugin executes requests via the native Rust HTTP stack (reqwest), which is **not subject to + WebView CORS or PNA rules at all**. + +## Decision + +1. **Introduce a thin runtime-aware HTTP layer** (`services/localServerHttp.ts`): + - Under `isTauriRuntime()` (canonical `__TAURI_INTERNALS__`-aware detection, see + `services/tauriRuntime.ts`) it dynamically imports `@tauri-apps/plugin-http` and uses its + `fetch` — native, CORS-free. + - Otherwise it uses the global `fetch`. The dynamic import keeps the web bundle lean and + matches the existing `@tauri-apps/*` externalization for web builds. + - The layer owns base-URL normalization (trailing-slash strip, `localhost:11434` default), + timeout composition (`AbortSignal.timeout` merged with the caller's signal via + `AbortSignal.any`), and error classification (`unreachable` | `timeout` vs. user `AbortError`, + which is rethrown unchanged so cancel-vs-failure stays distinguishable). +2. **Route all local-server traffic through it:** all four `ollamaService` functions and + `scanLocalOpenAiCompatibleEndpoints()`. Public signatures and legacy error strings are preserved + so orchestration-layer contracts (single `onError` firing, AbortError propagation) are untouched. +3. **Classified scan results:** the scan returns a `state` (`ok` | `unreachable` | `timeout` | + `http`) plus the legacy numeric `status`, so the UI can render actionable badges instead of a + bare "no response". +4. **PWA stays strictly desktop-only** (product decision): no reachability probing from the + browser. The `AiProviderCard` auto-effect and model loading are gated on `isTauriRuntime()`, so + the PWA performs **zero** localhost requests — the CORS console noise disappears by + construction. Instead the PWA shows a quiet banner explaining the restriction plus a + "Download the desktop app" CTA. +5. **CSP stays unchanged.** The WebView CSP is bypassed for plugin-http traffic (native stack); + the web CSP keeps its explicit localhost entries for defense-in-depth documentation, and the + `https:` BYOK trade-off from ADR 0004 is unaffected. +6. **Capability scope is pinned explicitly** in `src-tauri/capabilities/default.json`. Audit finding + during this work: `http:default` alone grants **no URL scope at all** (the plugin's + `Scope::is_allowed` requires a matching allow entry), so every plugin-http call — including the + existing AI-SDK `fetchAdapter` cloud calls on desktop — was silently denied. The scope now + allows `http://localhost:*/*` + `http://127.0.0.1:*/*` (all three well-known ports plus + user-configured custom ports on loopback) and the enumerated cloud endpoints that mirror the + Tauri CSP `connect-src` (Gemini, OpenAI, x.ai, OpenRouter, Groq). Known limitation (status quo, + unchanged): LAN-IP servers (`http://192.168.…`) and arbitrary BYOK cloud base URLs remain + outside the scope; widening is a separate, deliberate decision. + +## Consequences + +- **Positive:** Desktop Ollama/LM Studio/vLLM discovery and inference work out of the box — no + `OLLAMA_ORIGINS` setup required on desktop. PWA console stays clean. Timeouts, aborts, and error + classes are consistent across all local-server calls. Scan results are actionable (per-endpoint + badge + one-click "use this URL"). +- **Negative / accepted:** A second HTTP code path exists (plugin vs. browser fetch). It is + isolated in one ~100-line module and covered by unit tests that mock both branches. + `streamOllama`/`pullOllamaModel` rely on the plugin's streaming `Response.body` reader — covered + by mocked-reader tests; a native smoke check rides on the `tauri-build.yml` workflow dispatch. +- **Security posture:** unchanged-or-better. No new cloud endpoints, no secrets, localhost-only + capability scope, privacy-first (no call happens without a user-visible provider selection or + button press). + +## Alternatives considered + +- **Document `OLLAMA_ORIGINS=tauri://localhost,http://tauri.localhost` as the fix** — rejected: + pushes setup burden onto every desktop user, still breaks on LM Studio/vLLM CORS configs, and + does nothing for PNA/mixed-content quirks in WebView2/WKWebView. +- **Rust command wrapper (`invoke`) for Ollama** — rejected: duplicates an already-shipped plugin, + adds Rust surface for zero capability gain; plugin-http is the canonical Tauri v2 answer. +- **Allow PWA status-only probing with Private Network Access permission** — rejected (product + decision): keeps CORS noise possible, adds a second-class UX path, and conflicts with the + privacy-first "desktop-only" policy for localhost servers. diff --git a/locales/en/help.json b/locales/en/help.json index 6a4e7819..b0a377b3 100644 --- a/locales/en/help.json +++ b/locales/en/help.json @@ -71,7 +71,7 @@ "help.docs.pwaDesktop.title": "PWA & desktop packaging", "help.docs.ragPipeline.content": "

RAG & Prompt Assembly

WorldScript's retrieval-augmented generation (RAG) pipeline enriches every AI request with relevant passages from your own manuscript — so the model knows your story before it writes the next line.

", "help.docs.ragPipeline.title": "RAG & prompt assembly", - "help.docs.tauriDesktop.content": "

Tauri Desktop App

The WorldScript Studio desktop app wraps the same React codebase in a native Tauri v2 shell (Rust). It adds capabilities that browsers cannot provide while keeping your data fully local.

What the Desktop App Adds

Installers & Distribution

The Tauri CI workflow builds platform-specific installers on every tagged release (v*): .dmg for macOS (code-signed), .msi / .exe for Windows (code-signed), .AppImage and .deb for Linux. Installers are attached to GitHub Releases and referenced by the auto-updater endpoint.

Data Location

On desktop, data lives in the Tauri app data directory — typically %APPDATA%\\WorldScript Studio on Windows, ~/Library/Application Support/WorldScript Studio on macOS, and ~/.local/share/worldscript-studio on Linux. You can safely copy this directory for a full manual backup.

", + "help.docs.tauriDesktop.content": "

Tauri Desktop App

The WorldScript Studio desktop app wraps the same React codebase in a native Tauri v2 shell (Rust). It adds capabilities that browsers cannot provide while keeping your data fully local.

What the Desktop App Adds

Installers & Distribution

The Tauri CI workflow builds platform-specific installers on every tagged release (v*): .dmg for macOS (code-signed), .msi / .exe for Windows (code-signed), .AppImage and .deb for Linux. Installers are attached to GitHub Releases and referenced by the auto-updater endpoint.

Data Location

On desktop, data lives in the Tauri app data directory — typically %APPDATA%\\WorldScript Studio on Windows, ~/Library/Application Support/WorldScript Studio on macOS, and ~/.local/share/worldscript-studio on Linux. You can safely copy this directory for a full manual backup.

", "help.docs.tauriDesktop.title": "Tauri desktop app", "help.faq.api.content": "

Do I Need an API Key?

Only for cloud AI providers. You can use WorldScript for all writing, the Plot Board, characters, version control, and export without any API key. AI features with local providers also need no key.

Cloud providers (require an API key)

Local providers (no API key required)

Key security

Every API key is encrypted with AES-256-GCM (PBKDF2, 600,000 SHA-256 iterations) before being stored in IndexedDB. The plaintext key is never written to disk, never stored in localStorage, and never sent to any WorldScript server. You can store keys for multiple providers simultaneously and switch between them without re-entering them.

", "help.faq.api.title": "Do I need an API key?", @@ -79,7 +79,7 @@ "help.faq.offline.title": "Can I work offline?", "help.faq.privacy.content": "

Your Story Stays On Your Device

Yes, completely. WorldScript Studio is local-first by design — there is no WorldScript account, no cloud server, and no company that can access your manuscripts. All data lives in your browser's IndexedDB and OPFS, storage that only your device can read.

What stays local (everything, by default)

What leaves your device (only when you choose)

Go fully offline

Switch to a local AI provider — WebLLM in the browser or Ollama on the desktop app — or disable AI features entirely. In fully offline mode, zero data is transmitted anywhere. Writing, version control, export, and all settings work without any network connection.

", "help.faq.privacy.title": "Is my story private?", - "help.faq.providers.content": "

Which AI Provider Should I Use?

WorldScript supports multiple AI providers. Here is a quick guide to help you choose.

", + "help.faq.providers.content": "

Which AI Provider Should I Use?

WorldScript supports multiple AI providers. Here is a quick guide to help you choose.

", "help.faq.providers.title": "Which AI provider should I use?", "help.faq.saving.content": "

Your entire project, including all text and AI-generated images, is saved automatically and continuously in your web browser's local storage (a database called IndexedDB). This means your work is persisted on your computer between sessions. A 'Saving...' indicator appears in the header when changes are being written, followed by 'All changes saved'.

There is no cloud account or server-side storage. This ensures complete privacy but also means you are responsible for creating backups using the 'Export Backup' feature in Settings.

", "help.faq.saving.title": "How is my project data saved?", From fa31b2ea9657b3ef2b53161f4336edef236d8c45 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:47:02 +0200 Subject: [PATCH 02/14] fix(ai): route local-server http through tauri plugin-http (#266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New thin services/localServerHttp.ts: runtime-aware fetch (native @tauri-apps/plugin-http on desktop — CORS-free, browser fetch on web), shared base-URL normalization, timeout composition via AbortSignal.any, and unreachable/timeout error classification. User aborts rethrow unchanged (cancel != failure). ollamaService (test/list/stream/pull) and scanLocalOpenAiCompatibleEndpoints now use it; the scan returns per-endpoint state (ok/unreachable/timeout/http) for actionable UI badges. Public signatures and legacy error strings are preserved; new unit tests cover both fetch branches and classification. --- services/aiProviderService.ts | 35 ++++++-- services/localServerHttp.ts | 107 +++++++++++++++++++++++ services/ollamaService.ts | 33 +++---- tests/unit/aiProviderService.test.ts | 58 +++++++++++++ tests/unit/localServerHttp.test.ts | 123 +++++++++++++++++++++++++++ tests/unit/ollamaService.test.ts | 8 ++ 6 files changed, 340 insertions(+), 24 deletions(-) create mode 100644 services/localServerHttp.ts create mode 100644 tests/unit/localServerHttp.test.ts diff --git a/services/aiProviderService.ts b/services/aiProviderService.ts index ee55f159..6c3183fd 100644 --- a/services/aiProviderService.ts +++ b/services/aiProviderService.ts @@ -37,6 +37,7 @@ import { streamText as streamTextGemini, } from './geminiService'; import { generateLocalText } from './localAiFacade'; +import { LocalServerError, localServerFetch } from './localServerHttp'; import { listOllamaModels as listOllamaModelsFromService, streamOllama, @@ -686,24 +687,40 @@ export async function listOllamaModels(baseUrl = 'http://localhost:11434'): Prom return listOllamaModelsFromService(baseUrl); } -/** QNBS-v3: Schneller Desktop-Check typischer lokaler /v1-Endpunkte — keine Secrets, nur Erreichbarkeit. */ -export async function scanLocalOpenAiCompatibleEndpoints(): Promise< - { labelKey: string; baseUrl: string; ok: boolean; status?: number }[] -> { +/** QNBS-v3: classified reachability of a scanned local endpoint (#266). */ +export type LocalEndpointScanState = 'ok' | 'unreachable' | 'timeout' | 'http'; + +export interface LocalEndpointScanResult { + labelKey: string; + baseUrl: string; + ok: boolean; + state: LocalEndpointScanState; + /** Numeric HTTP status when the server answered (incl. error statuses). */ + status?: number; +} + +/** + * QNBS-v3: Schneller Desktop-Check typischer lokaler /v1-Endpunkte — keine Secrets, nur + * Erreichbarkeit. #266: routed through localServerFetch (Tauri plugin-http on desktop) so the + * scan works inside the WebView, with per-endpoint state classification for actionable UI badges. + */ +export async function scanLocalOpenAiCompatibleEndpoints(): Promise { const candidates = [ { labelKey: 'settings.ai.scanLabelOllama', baseUrl: 'http://localhost:11434' }, { labelKey: 'settings.ai.scanLabelLmStudio', baseUrl: 'http://localhost:1234' }, { labelKey: 'settings.ai.scanLabelVllm', baseUrl: 'http://localhost:8000' }, ]; return Promise.all( - candidates.map(async ({ labelKey, baseUrl }) => { + candidates.map(async ({ labelKey, baseUrl }): Promise => { try { const root = normalizeOpenAiCompatibleBaseUrl(baseUrl); - const res = await fetch(`${root}/models`, { signal: AbortSignal.timeout(2800) }); + const res = await localServerFetch(`${root}/models`, { timeoutMs: 2800 }); const ok = res.ok || res.status === 401; - return { labelKey, baseUrl, ok, status: res.status }; - } catch { - return { labelKey, baseUrl, ok: false }; + return { labelKey, baseUrl, ok, state: ok ? 'ok' : 'http', status: res.status }; + } catch (err) { + const state: LocalEndpointScanState = + err instanceof LocalServerError && err.kind === 'timeout' ? 'timeout' : 'unreachable'; + return { labelKey, baseUrl, ok: false, state }; } }), ); diff --git a/services/localServerHttp.ts b/services/localServerHttp.ts new file mode 100644 index 00000000..499c72cf --- /dev/null +++ b/services/localServerHttp.ts @@ -0,0 +1,107 @@ +/** + * Runtime-aware HTTP layer for local inference servers (Ollama, LM Studio, vLLM). + * + * QNBS-v3 (#266, ADR-0012): inside the Tauri WebView, browser `fetch` to `http://localhost:*` is + * cross-origin and dies on CORS/PNA unless the server opts in — so desktop discovery silently saw + * nothing. Under Tauri we route through `@tauri-apps/plugin-http` (native reqwest stack, no CORS); + * on the web we keep the global fetch. The plugin is imported dynamically so the web bundle never + * loads it. Kept deliberately thin: URL normalization, timeout composition, error classification. + */ +import { isTauriRuntime } from './tauriRuntime'; + +export type LocalServerErrorKind = 'unreachable' | 'timeout'; + +/** Classified local-server failure. User aborts are NOT wrapped — they rethrow unchanged. */ +export class LocalServerError extends Error { + readonly kind: LocalServerErrorKind; + + constructor(kind: LocalServerErrorKind, message: string, options?: { cause?: unknown }) { + super(message, options); + this.name = 'LocalServerError'; + this.kind = kind; + } +} + +export const DEFAULT_OLLAMA_BASE_URL = 'http://localhost:11434'; + +/** Trims whitespace and trailing slashes; falls back to the Ollama default when empty. */ +export function normalizeLocalBaseUrl( + baseUrl?: string, + fallback: string = DEFAULT_OLLAMA_BASE_URL, +): string { + const resolved = baseUrl?.trim() || fallback; + return resolved.replace(/\/+$/, ''); +} + +// QNBS-v3: shape-based checks — DOMException is not an instanceof Error in some runtimes. +export function isAbortError(err: unknown): boolean { + return ( + typeof err === 'object' && err !== null && (err as { name?: string }).name === 'AbortError' + ); +} + +export function isTimeoutError(err: unknown): boolean { + return ( + typeof err === 'object' && err !== null && (err as { name?: string }).name === 'TimeoutError' + ); +} + +export interface LocalServerFetchInit { + method?: string; + headers?: Record; + body?: string; + /** Caller cancellation. Abort errors propagate unchanged (cancel ≠ failure). */ + signal?: AbortSignal | null; + /** Wall-clock timeout merged with `signal` via AbortSignal.any. */ + timeoutMs?: number; +} + +/** Picks the native Tauri HTTP plugin on desktop, global fetch on the web. */ +async function resolveFetch(): Promise { + if (isTauriRuntime()) { + const { fetch: tauriFetch } = await import('@tauri-apps/plugin-http'); + return tauriFetch as unknown as typeof fetch; + } + return globalThis.fetch.bind(globalThis); +} + +function composeSignal(signal: AbortSignal | null | undefined, timeoutMs?: number) { + if (timeoutMs === undefined) return signal ?? null; + const timeoutSignal = AbortSignal.timeout(timeoutMs); + if (!signal) return timeoutSignal; + // QNBS-v3: AbortSignal.any ships in Node 22 + all target browsers; fall back to the timeout + // signal alone if an exotic runtime lacks it (caller cancel then no-ops, never crashes). + return typeof AbortSignal.any === 'function' + ? AbortSignal.any([signal, timeoutSignal]) + : timeoutSignal; +} + +/** + * fetch() for local servers. Throws LocalServerError('unreachable' | 'timeout') on transport + * failures; rethrows the original AbortError for caller-initiated cancels; returns the Response + * otherwise (HTTP status classification stays with the caller). + */ +export async function localServerFetch( + url: string, + init: LocalServerFetchInit = {}, +): Promise { + const fetchImpl = await resolveFetch(); + const requestInit: RequestInit = { + ...(init.method !== undefined ? { method: init.method } : {}), + ...(init.headers !== undefined ? { headers: init.headers } : {}), + ...(init.body !== undefined ? { body: init.body } : {}), + signal: composeSignal(init.signal, init.timeoutMs), + }; + try { + return await fetchImpl(url, requestInit); + } catch (err) { + if (isAbortError(err)) throw err; + if (isTimeoutError(err)) { + throw new LocalServerError('timeout', `Local server timed out (${url})`, { cause: err }); + } + const message = err instanceof Error ? err.message : String(err); + throw new LocalServerError('unreachable', `Local server not reachable (${url}): ${message}`, { + cause: err, + }); + } +} diff --git a/services/ollamaService.ts b/services/ollamaService.ts index 78a1223b..c8941950 100644 --- a/services/ollamaService.ts +++ b/services/ollamaService.ts @@ -1,7 +1,12 @@ -const normalizeBaseUrl = (baseUrl?: string): string => { - const resolved = baseUrl?.trim() || 'http://localhost:11434'; - return resolved.replace(/\/+$/, ''); -}; +import { + isAbortError, + LocalServerError, + localServerFetch, + normalizeLocalBaseUrl, +} from './localServerHttp'; + +// QNBS-v3 (#266): canonical normalization lives in localServerHttp (shared with the scanner). +const normalizeBaseUrl = normalizeLocalBaseUrl; const stripControlChars = (value: string): string => { let output = ''; @@ -35,13 +40,6 @@ export interface OllamaStreamCallbacks { onError?: (error: Error) => void; } -// QNBS-v3: shape-based AbortError check — DOMException is not an instanceof Error in some runtimes. -function isAbortError(err: unknown): boolean { - return ( - typeof err === 'object' && err !== null && (err as { name?: string }).name === 'AbortError' - ); -} - export interface OllamaPullProgress { /** Ollama status line, e.g. "pulling manifest", "downloading …", "verifying", "success". */ status: string; @@ -70,7 +68,8 @@ export async function pullOllamaModel(name: string, opts: OllamaPullOptions = {} let response: Response; try { - response = await fetch(`${baseUrl}/api/pull`, { + // QNBS-v3 (#266): Tauri-aware fetch — native plugin-http on desktop (CORS-free), web fetch else. + response = await localServerFetch(`${baseUrl}/api/pull`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: model, stream: true }), @@ -139,7 +138,7 @@ export async function pullOllamaModel(name: string, opts: OllamaPullOptions = {} export async function listOllamaModels(baseUrl?: string): Promise { const url = `${normalizeBaseUrl(baseUrl)}/api/tags`; try { - const res = await fetch(url, { signal: AbortSignal.timeout(5000) as unknown as AbortSignal }); + const res = await localServerFetch(url, { timeoutMs: 5000 }); if (!res.ok) return []; const payload = await res.json(); return Array.isArray(payload.models) @@ -155,10 +154,14 @@ export async function testOllamaConnection( ): Promise<{ ok: boolean; error?: string }> { const url = `${normalizeBaseUrl(baseUrl)}/api/tags`; try { - const res = await fetch(url, { signal: AbortSignal.timeout(5000) as unknown as AbortSignal }); + const res = await localServerFetch(url, { timeoutMs: 5000 }); if (!res.ok) return { ok: false, error: `Ollama HTTP ${res.status}` }; return { ok: true }; } catch (error: unknown) { + // QNBS-v3 (#266): classified failures — distinguish a hanging server from a missing one. + if (error instanceof LocalServerError && error.kind === 'timeout') { + return { ok: false, error: `Ollama timed out (${normalizeBaseUrl(baseUrl)})` }; + } const message = error instanceof Error ? error.message : String(error); return { ok: false, @@ -186,7 +189,7 @@ export async function streamOllama( let response: Response; try { - response = await fetch(`${baseUrl}/api/generate`, { + response = await localServerFetch(`${baseUrl}/api/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), diff --git a/tests/unit/aiProviderService.test.ts b/tests/unit/aiProviderService.test.ts index dd3a7c40..b511e0ec 100644 --- a/tests/unit/aiProviderService.test.ts +++ b/tests/unit/aiProviderService.test.ts @@ -287,6 +287,33 @@ describe('testAIConnection', () => { }); }); +describe('testAIConnection — ollama desktop branch', () => { + afterEach(() => { + delete (window as { __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__; + }); + + it('delegates to testOllamaConnection under Tauri and returns its result', async () => { + (window as { __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__ = {}; + const { testOllamaConnection } = await import('../../services/ollamaService'); + vi.mocked(testOllamaConnection).mockResolvedValueOnce({ ok: true }); + const result = await testAIConnection('ollama', { ollamaBaseUrl: 'http://host:11434' }); + expect(result.ok).toBe(true); + expect(testOllamaConnection).toHaveBeenCalledWith('http://host:11434'); + }); + + it('propagates the service error under Tauri (e.g. classified timeout)', async () => { + (window as { __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__ = {}; + const { testOllamaConnection } = await import('../../services/ollamaService'); + vi.mocked(testOllamaConnection).mockResolvedValueOnce({ + ok: false, + error: 'Ollama timed out (http://localhost:11434)', + }); + const result = await testAIConnection('ollama', {}); + expect(result.ok).toBe(false); + expect(result.error).toContain('timed out'); + }); +}); + // ─── streamText (OpenAI signal + Ollama→Gemini fallback) ──────────────────── describe('streamText OpenAI', () => { @@ -650,9 +677,40 @@ describe('scanLocalOpenAiCompatibleEndpoints', () => { const results = await scanLocalOpenAiCompatibleEndpoints(); for (const r of results) { expect(r.ok).toBe(true); + expect(r.state).toBe('ok'); expect(r.status).toBe(401); } }); + + it('classifies non-ok HTTP responses as state:http with the numeric status', async () => { + globalThis.fetch = vi.fn().mockResolvedValue({ ok: false, status: 500 } as Response); + const results = await scanLocalOpenAiCompatibleEndpoints(); + for (const r of results) { + expect(r.ok).toBe(false); + expect(r.state).toBe('http'); + expect(r.status).toBe(500); + } + }); + + it('classifies TimeoutError-shaped rejections as state:timeout', async () => { + globalThis.fetch = vi + .fn() + .mockRejectedValue(Object.assign(new Error('timed out'), { name: 'TimeoutError' })); + const results = await scanLocalOpenAiCompatibleEndpoints(); + for (const r of results) { + expect(r.ok).toBe(false); + expect(r.state).toBe('timeout'); + } + }); + + it('classifies plain network failures as state:unreachable', async () => { + globalThis.fetch = vi.fn().mockRejectedValue(new TypeError('ECONNREFUSED')); + const results = await scanLocalOpenAiCompatibleEndpoints(); + for (const r of results) { + expect(r.ok).toBe(false); + expect(r.state).toBe('unreachable'); + } + }); }); // ─── Service-level request deduplication ───────────────────────────────────── diff --git a/tests/unit/localServerHttp.test.ts b/tests/unit/localServerHttp.test.ts new file mode 100644 index 00000000..7aea055d --- /dev/null +++ b/tests/unit/localServerHttp.test.ts @@ -0,0 +1,123 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +const tauriFetchMock = vi.fn(); + +vi.mock('@tauri-apps/plugin-http', () => ({ + fetch: (...args: unknown[]) => tauriFetchMock(...args), +})); + +const isTauriRuntimeMock = vi.fn(() => false); +vi.mock('../../services/tauriRuntime', () => ({ + isTauriRuntime: () => isTauriRuntimeMock(), +})); + +import { + DEFAULT_OLLAMA_BASE_URL, + LocalServerError, + localServerFetch, + normalizeLocalBaseUrl, +} from '../../services/localServerHttp'; + +beforeEach(() => { + vi.stubGlobal('fetch', vi.fn()); + tauriFetchMock.mockReset(); + isTauriRuntimeMock.mockReturnValue(false); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +// ─── normalizeLocalBaseUrl ──────────────────────────────────────────────────── + +describe('normalizeLocalBaseUrl', () => { + it('falls back to the Ollama default for empty/undefined input', () => { + expect(normalizeLocalBaseUrl()).toBe(DEFAULT_OLLAMA_BASE_URL); + expect(normalizeLocalBaseUrl(' ')).toBe(DEFAULT_OLLAMA_BASE_URL); + }); + + it('trims whitespace and strips trailing slashes', () => { + expect(normalizeLocalBaseUrl(' http://myhost:1234// ')).toBe('http://myhost:1234'); + }); +}); + +// ─── web branch ─────────────────────────────────────────────────────────────── + +describe('localServerFetch (web branch)', () => { + it('uses the global fetch and forwards method/headers/body', async () => { + vi.mocked(fetch).mockResolvedValueOnce(new Response('{}', { status: 200 })); + await localServerFetch('http://localhost:11434/api/tags', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: '{"a":1}', + }); + expect(fetch).toHaveBeenCalledWith( + 'http://localhost:11434/api/tags', + expect.objectContaining({ + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: '{"a":1}', + }), + ); + expect(tauriFetchMock).not.toHaveBeenCalled(); + }); + + it('omits unset init keys (exactOptionalPropertyTypes hygiene)', async () => { + vi.mocked(fetch).mockResolvedValueOnce(new Response('{}', { status: 200 })); + await localServerFetch('http://localhost:11434/api/tags'); + const init = vi.mocked(fetch).mock.calls[0]?.[1] as RequestInit; + expect('method' in init).toBe(false); + expect('headers' in init).toBe(false); + expect('body' in init).toBe(false); + }); + + it('always provides a signal when timeoutMs is set', async () => { + vi.mocked(fetch).mockResolvedValueOnce(new Response('{}', { status: 200 })); + await localServerFetch('http://localhost:11434/api/tags', { timeoutMs: 1000 }); + const init = vi.mocked(fetch).mock.calls[0]?.[1] as RequestInit; + expect(init.signal).toBeInstanceOf(AbortSignal); + }); +}); + +// ─── tauri branch ───────────────────────────────────────────────────────────── + +describe('localServerFetch (tauri branch)', () => { + it('uses @tauri-apps/plugin-http instead of the global fetch', async () => { + isTauriRuntimeMock.mockReturnValue(true); + tauriFetchMock.mockResolvedValueOnce(new Response('{}', { status: 200 })); + await localServerFetch('http://localhost:11434/api/tags', { timeoutMs: 5000 }); + expect(tauriFetchMock).toHaveBeenCalledWith( + 'http://localhost:11434/api/tags', + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + expect(fetch).not.toHaveBeenCalled(); + }); +}); + +// ─── error classification ───────────────────────────────────────────────────── + +describe('localServerFetch error classification', () => { + it('wraps network failures as LocalServerError(unreachable) with url + cause message', async () => { + vi.mocked(fetch).mockRejectedValueOnce(new TypeError('Connection refused')); + const err = await localServerFetch('http://localhost:11434/api/tags').catch((e) => e); + expect(err).toBeInstanceOf(LocalServerError); + expect(err.kind).toBe('unreachable'); + expect(err.message).toContain('localhost:11434'); + expect(err.message).toContain('Connection refused'); + }); + + it('wraps TimeoutError-shaped rejections as LocalServerError(timeout)', async () => { + const timeoutErr = Object.assign(new Error('timed out'), { name: 'TimeoutError' }); + vi.mocked(fetch).mockRejectedValueOnce(timeoutErr); + const err = await localServerFetch('http://localhost:11434/api/tags').catch((e) => e); + expect(err).toBeInstanceOf(LocalServerError); + expect(err.kind).toBe('timeout'); + }); + + it('rethrows caller AbortError unchanged (cancel is not a failure)', async () => { + const abortErr = Object.assign(new Error('aborted'), { name: 'AbortError' }); + vi.mocked(fetch).mockRejectedValueOnce(abortErr); + const err = await localServerFetch('http://localhost:11434/api/tags').catch((e) => e); + expect(err).toBe(abortErr); + }); +}); diff --git a/tests/unit/ollamaService.test.ts b/tests/unit/ollamaService.test.ts index 5339747e..f8e29664 100644 --- a/tests/unit/ollamaService.test.ts +++ b/tests/unit/ollamaService.test.ts @@ -85,6 +85,14 @@ describe('testOllamaConnection', () => { expect(result.error).toContain('localhost:11434'); expect(result.error).toContain('Connection refused'); }); + + it('classifies a TimeoutError-shaped rejection as a timeout (#266)', async () => { + const timeoutErr = Object.assign(new Error('timed out'), { name: 'TimeoutError' }); + vi.mocked(fetch).mockRejectedValueOnce(timeoutErr); + const result = await testOllamaConnection('http://localhost:11434'); + expect(result.ok).toBe(false); + expect(result.error).toContain('timed out'); + }); }); // ─── streamOllama ───────────────────────────────────────────────────────────── From 449cfdd2d0c5ba77a466bc89598875e5fd6340a7 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:47:27 +0200 Subject: [PATCH 03/14] fix(settings): desktop-gate ollama probing, PWA banner + CTA, scan badges (#266) - The settings auto-effect and model loading no longer probe localhost in the PWA (that was the CORS console noise); a quiet 'desktop app required' banner with a download CTA replaces it. testAIConnection's desktop-only guard is unchanged. - Desktop scan results render classified status badges (reachable / no response / timeout / HTTP error) with aria-live, plus a one-click 'Use this URL' action that adopts the found base URL + matching preset. - Tauri http capability: http:default alone grants NO url scope (plugin allow-list denied every call, incl. desktop cloud AI). Scope now allows loopback any-port + the cloud endpoints mirroring the Tauri CSP. --- components/settings/AiProviderCard.tsx | 86 ++++++++++--- src-tauri/capabilities/default.json | 14 ++- tests/unit/settings/AiProviderCard.test.tsx | 126 +++++++++++++++++++- 3 files changed, 204 insertions(+), 22 deletions(-) diff --git a/components/settings/AiProviderCard.tsx b/components/settings/AiProviderCard.tsx index c0662714..f587a21a 100644 --- a/components/settings/AiProviderCard.tsx +++ b/components/settings/AiProviderCard.tsx @@ -6,6 +6,7 @@ import { LOCAL_BACKEND_PRESET_DEFAULT_URL } from '../../services/ai/localBackend import type { WebGpuAdapterInfo } from '../../services/ai/webGpuDetectorService'; import { detectWebGpuDetails } from '../../services/ai/webGpuDetectorService'; import { + type LocalEndpointScanResult, listOllamaModels, scanLocalOpenAiCompatibleEndpoints, testAIConnection, @@ -46,9 +47,7 @@ export const AiProviderCard: FC = ({ const [isLoadingModels, setIsLoadingModels] = useState(false); const [isSavingKey, setIsSavingKey] = useState(false); const [scanBusy, setScanBusy] = useState(false); - const [scanRows, setScanRows] = useState<{ labelKey: string; baseUrl: string; ok: boolean }[]>( - [], - ); + const [scanRows, setScanRows] = useState([]); // QNBS-v3: GPU probe runs once when WebLLM tab is selected — no polling. const [gpuInfo, setGpuInfo] = useState(null); @@ -73,6 +72,12 @@ export const AiProviderCard: FC = ({ }, [openaiKey]); const handleLoadOllamaModels = useCallback(async () => { + // QNBS-v3 (#266): never probe localhost from the PWA — the request is CORS/PNA-blocked anyway + // and only produces console noise. Local servers are a desktop-only feature by policy. + if (!isTauriRuntime()) { + setOllamaModels([]); + return; + } setIsLoadingModels(true); try { const models = await listOllamaModels(ollamaBaseUrl); @@ -107,15 +112,30 @@ export const AiProviderCard: FC = ({ const handleScanLocals = useCallback(async () => { setScanBusy(true); try { - const rows = await scanLocalOpenAiCompatibleEndpoints(); - setScanRows(rows.map((r) => ({ labelKey: r.labelKey, baseUrl: r.baseUrl, ok: r.ok }))); + setScanRows(await scanLocalOpenAiCompatibleEndpoints()); } finally { setScanBusy(false); } }, []); + // QNBS-v3 (#266): one-click adopt of a discovered server URL (+ matching preset when known). + const handleUseScannedUrl = useCallback( + (baseUrl: string) => { + const presetEntry = ( + Object.entries(LOCAL_BACKEND_PRESET_DEFAULT_URL) as [LocalBackendPreset, string][] + ).find(([preset, url]) => preset !== 'custom' && url === baseUrl); + onAdvancedAiPatch({ + ollamaBaseUrl: baseUrl, + localBackendPreset: presetEntry ? presetEntry[0] : 'custom', + }); + }, + [onAdvancedAiPatch], + ); + useEffect(() => { - if (provider === 'ollama') { + // QNBS-v3 (#266): the ollama auto-probe (models + connection test) only runs on desktop. + // In the PWA it fired CORS-blocked localhost requests on every settings visit. + if (provider === 'ollama' && isDesktop) { void handleLoadOllamaModels(); void handleTest(); } else if (provider === 'webllm') { @@ -125,7 +145,7 @@ export const AiProviderCard: FC = ({ .then(setGpuInfo) .catch(() => setGpuInfo({ status: 'unknown' })); } - }, [provider, handleLoadOllamaModels, handleTest]); + }, [provider, isDesktop, handleLoadOllamaModels, handleTest]); const providers: { id: AIProvider; label: string }[] = [ { id: 'gemini', label: 'Google Gemini' }, @@ -272,12 +292,23 @@ export const AiProviderCard: FC = ({ {provider === 'ollama' && (
{!isDesktop && ( -
-

+ // QNBS-v3 (#266): quiet banner instead of CORS console noise — the PWA never + // auto-probes localhost, so this is the only place the restriction surfaces. +

+

-

{t('settings.ai.ollamaBrowserNote')}

+

{t('settings.ai.ollamaDesktopOnlyBody')}

+ +
)} {isDesktop && ( @@ -345,17 +376,36 @@ export const AiProviderCard: FC = ({ {scanBusy ? : t('settings.ai.scanLocalPorts')} {scanRows.length > 0 && ( -
    +
      {scanRows.map((row) => ( -
    • - {t(row.labelKey)} — {row.baseUrl}{' '} +
    • + + {t(row.labelKey)} — {row.baseUrl} + - {row.ok ? t('settings.ai.scanOk') : t('settings.ai.scanNo')} + {row.state === 'ok' && t('settings.ai.scanOk')} + {row.state === 'unreachable' && t('settings.ai.scanNo')} + {row.state === 'timeout' && t('settings.ai.scanStateTimeout')} + {row.state === 'http' && + `${t('settings.ai.scanStateHttp')}${row.status ? ` (${row.status})` : ''}`} + {row.ok && ( + + )}
    • ))}
    diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 624ece24..8db4b222 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -14,7 +14,19 @@ "dialog:default", "dialog:allow-open", "dialog:allow-save", - "http:default", + { + "identifier": "http:default", + "allow": [ + "http://localhost:*/*", + "http://127.0.0.1:*/*", + "https://generativelanguage.googleapis.com/*", + "https://api.openai.com/*", + "https://api.x.ai/*", + "https://openrouter.ai/*", + "https://api.openrouter.ai/*", + "https://api.groq.com/*" + ] + }, "shell:allow-open", "updater:default", "core:tray:default", diff --git a/tests/unit/settings/AiProviderCard.test.tsx b/tests/unit/settings/AiProviderCard.test.tsx index c92657e0..b9bba98e 100644 --- a/tests/unit/settings/AiProviderCard.test.tsx +++ b/tests/unit/settings/AiProviderCard.test.tsx @@ -1,6 +1,12 @@ -import { render, screen } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { AiProviderCard } from '../../../components/settings/AiProviderCard'; +import { + listOllamaModels, + scanLocalOpenAiCompatibleEndpoints, + testAIConnection, +} from '../../../services/aiProviderService'; // --------------------------------------------------------------------------- // Mocks @@ -25,7 +31,12 @@ vi.mock('../../../services/aiProviderService', () => ({ })); vi.mock('../../../services/ai/localBackendPresets', () => ({ - LOCAL_BACKEND_PRESET_DEFAULT_URL: 'http://localhost:11434', + LOCAL_BACKEND_PRESET_DEFAULT_URL: { + ollama_default: 'http://localhost:11434', + lm_studio: 'http://localhost:1234', + vllm: 'http://localhost:8000', + custom: 'http://localhost:11434', + }, })); const mockAdvancedAi = { @@ -51,6 +62,22 @@ const mockAdvancedAi = { const mockOnAdvancedAiPatch = vi.fn(); const mockOnProviderChange = vi.fn(); +const ollamaAdvancedAi = { ...mockAdvancedAi, provider: 'ollama' as const }; + +function setDesktopRuntime(enabled: boolean): void { + const w = window as Window & { __TAURI_INTERNALS__?: unknown }; + if (enabled) { + w.__TAURI_INTERNALS__ = {}; + } else { + delete w.__TAURI_INTERNALS__; + } +} + +afterEach(() => { + setDesktopRuntime(false); + vi.clearAllMocks(); +}); + // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- @@ -103,3 +130,96 @@ describe('AiProviderCard', () => { expect(screen.getByText('settings.ai.providerDescription')).toBeTruthy(); }); }); + +// ─── #266: ollama in the PWA vs desktop ────────────────────────────────────── + +describe('AiProviderCard — ollama provider (#266)', () => { + it('PWA: shows the desktop-only banner with download CTA and never probes localhost', async () => { + setDesktopRuntime(false); + render( + , + ); + + expect(screen.getByText('settings.ai.ollamaDesktopOnlyTitle')).toBeTruthy(); + expect(screen.getByText('settings.ai.ollamaDesktopOnlyBody')).toBeTruthy(); + const cta = screen.getByRole('link', { name: /downloadDesktopCta/ }); + expect(cta.getAttribute('href')).toContain('github.com/qnbs/WorldScript-Studio/releases'); + expect(cta.getAttribute('rel')).toContain('noreferrer'); + + // QNBS-v3 (#266): no auto-fetch in the browser — this is what killed the CORS console noise. + await waitFor(() => { + expect(screen.getByText('settings.ai.ollamaDesktopOnlyTitle')).toBeTruthy(); + }); + expect(listOllamaModels).not.toHaveBeenCalled(); + expect(testAIConnection).not.toHaveBeenCalled(); + }); + + it('desktop: auto-loads models and tests the connection when ollama is selected', async () => { + setDesktopRuntime(true); + render( + , + ); + + await waitFor(() => { + expect(listOllamaModels).toHaveBeenCalled(); + expect(testAIConnection).toHaveBeenCalledWith('ollama', expect.any(Object)); + }); + expect(screen.queryByText('settings.ai.ollamaDesktopOnlyTitle')).toBeNull(); + }); + + it('desktop: scan renders classified status badges and the use-url action patches settings', async () => { + setDesktopRuntime(true); + vi.mocked(scanLocalOpenAiCompatibleEndpoints).mockResolvedValueOnce([ + { + labelKey: 'settings.ai.scanLabelOllama', + baseUrl: 'http://localhost:11434', + ok: true, + state: 'ok', + status: 200, + }, + { + labelKey: 'settings.ai.scanLabelLmStudio', + baseUrl: 'http://localhost:1234', + ok: false, + state: 'timeout', + }, + { + labelKey: 'settings.ai.scanLabelVllm', + baseUrl: 'http://localhost:8000', + ok: false, + state: 'http', + status: 500, + }, + ]); + const user = userEvent.setup(); + render( + , + ); + + await user.click(screen.getByRole('button', { name: 'settings.ai.scanLocalPorts' })); + + await waitFor(() => { + expect(screen.getByText('settings.ai.scanOk')).toBeTruthy(); + }); + expect(screen.getByText('settings.ai.scanStateTimeout')).toBeTruthy(); + expect(screen.getByText(/scanStateHttp/)).toBeTruthy(); + + await user.click(screen.getByRole('button', { name: 'settings.ai.scanUseUrl' })); + expect(mockOnAdvancedAiPatch).toHaveBeenCalledWith({ + ollamaBaseUrl: 'http://localhost:11434', + localBackendPreset: 'ollama_default', + }); + }); +}); From ff53d493669ff517a43dd176f016c1a537892063 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:47:32 +0200 Subject: [PATCH 04/14] feat(i18n): local-server strings for all 19 locales (#266) New settings.ai keys (desktop-only banner title/body, download CTA, scan timeout/HTTP states, use-this-URL) plus a corrected ollamaHint (no CORS setup needed on desktop), translated for all 19 locales; runtime bundles rebuilt (53827 keys). --- locales/ar/settings.json | 8 +- locales/de/settings.json | 52 ++--- locales/el/settings.json | 8 +- locales/en/settings.json | 358 ++++++++++++++++----------------- locales/es/settings.json | 52 ++--- locales/eu/settings.json | 8 +- locales/fa/settings.json | 8 +- locales/fi/settings.json | 8 +- locales/fr/settings.json | 52 ++--- locales/he/settings.json | 8 +- locales/hu/settings.json | 8 +- locales/is/settings.json | 8 +- locales/it/settings.json | 52 ++--- locales/ja/settings.json | 8 +- locales/ko/settings.json | 8 +- locales/pt/settings.json | 8 +- locales/ru/settings.json | 8 +- locales/sv/settings.json | 8 +- locales/zh/settings.json | 8 +- public/locales/ar/bundle.json | 8 +- public/locales/de/bundle.json | 50 ++--- public/locales/el/bundle.json | 8 +- public/locales/en/bundle.json | 360 +++++++++++++++++----------------- public/locales/es/bundle.json | 50 ++--- public/locales/eu/bundle.json | 8 +- public/locales/fa/bundle.json | 8 +- public/locales/fi/bundle.json | 8 +- public/locales/fr/bundle.json | 50 ++--- public/locales/he/bundle.json | 8 +- public/locales/hu/bundle.json | 8 +- public/locales/is/bundle.json | 8 +- public/locales/it/bundle.json | 50 ++--- public/locales/ja/bundle.json | 8 +- public/locales/ko/bundle.json | 8 +- public/locales/pt/bundle.json | 8 +- public/locales/ru/bundle.json | 8 +- public/locales/sv/bundle.json | 8 +- public/locales/zh/bundle.json | 8 +- 38 files changed, 789 insertions(+), 561 deletions(-) diff --git a/locales/ar/settings.json b/locales/ar/settings.json index 76082b66..a16df146 100644 --- a/locales/ar/settings.json +++ b/locales/ar/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "مستوى إبداع الذكاء الاصطناعي", "settings.ai.creativityDescription": "القيم الأعلى تنتج نتائج أكثر غير متوقّعة.", "settings.ai.customModel": "نموذج مخصّص", + "settings.ai.downloadDesktopCta": "تنزيل تطبيق سطح المكتب", "settings.ai.fallbackNone": "لا شيء", "settings.ai.fallbackStep1": "الاحتياطي الأول", "settings.ai.fallbackStep2": "الاحتياطي الثاني", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "إعداد مسبق للخلفية المحلية", "settings.ai.ollamaBrowserNote": "‏Ollama متاح فقط في تطبيق سطح المكتب. تمنع سياسة أمان المحتوى للمتصفّح الاتصالات المباشرة بـ localhost.", - "settings.ai.ollamaHint": "تأكّد من تشغيل ollama serve وتفعيل CORS.", + "settings.ai.ollamaDesktopOnlyBody": "يتوفر Ollama والخوادم المحلية المتوافقة مع OpenAI (LM Studio وvLLM) فقط في تطبيق سطح المكتب. تحظر المتصفحات الاتصالات المباشرة بـ localhost (سياسة أمان المحتوى والوصول إلى الشبكة الخاصة).", + "settings.ai.ollamaDesktopOnlyTitle": "تطبيق سطح المكتب مطلوب للخوادم المحلية", + "settings.ai.ollamaHint": "تأكد من تشغيل الخادم (مثل ollama serve). يتصل تطبيق سطح المكتب مباشرة — دون الحاجة إلى إعداد CORS.", "settings.ai.ollamaModelHint": "نماذج اختيار سريع مُبلَّغ عنها من خادمك — انقر للاستخدام.", "settings.ai.ollamaServerUrl": "عنوان خادم Ollama", "settings.ai.ollamaTauriBypass": "بناء سطح المكتب: يستدعي WorldScript ‏Ollama مباشرة — بلا حاجز CORS للمتصفّح.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "مسح المنافذ المحلية الشائعة", "settings.ai.scanNo": "لا استجابة", "settings.ai.scanOk": "يمكن الوصول إليه", + "settings.ai.scanStateHttp": "خطأ HTTP", + "settings.ai.scanStateTimeout": "انتهت المهلة", + "settings.ai.scanUseUrl": "استخدام هذا الرابط", "settings.ai.temperature.balanced": "1 – متوازن", "settings.ai.temperature.creative": "2 – إبداعي", "settings.ai.temperature.precise": "0 – دقيق", diff --git a/locales/de/settings.json b/locales/de/settings.json index fd4fad65..6214c63a 100644 --- a/locales/de/settings.json +++ b/locales/de/settings.json @@ -13,6 +13,7 @@ "settings.about.githubDescription": "Quellcode ansehen, Fehler melden und mitmachen.", "settings.about.githubLabel": "Open-Source auf GitHub", "settings.about.liveDemo": "Live-Demo ausprobieren", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Desktop-Laufzeitversion", "settings.about.title": "Über WorldScript Studio", "settings.about.versionLabel": "Version", @@ -63,16 +64,16 @@ "settings.advancedAi.model": "KI-Modell", "settings.advancedAi.modelDescription": "Das KI-Modell für Szenengeneration, Analyse und andere KI-Funktionen. Die Verfügbarkeit hängt vom gewählten Anbieter ab.", "settings.advancedAi.modelRecommendationsIntro": "Beliebte lokale Checkpoints (Namen im Runtime überprüfen):", - "settings.advancedAi.ollamaPull.recommendedFor": "Für dein Gerät empfohlen:", + "settings.advancedAi.ollamaPull.batteryNote": "Eine Größe kleiner gewählt, um Akku zu sparen.", + "settings.advancedAi.ollamaPull.installed": "Installiert", "settings.advancedAi.ollamaPull.pull": "Modell laden", "settings.advancedAi.ollamaPull.pulling": "Modell wird geladen…", + "settings.advancedAi.ollamaPull.recommendedFor": "Für dein Gerät empfohlen:", "settings.advancedAi.ollamaPull.retry": "Erneut versuchen", - "settings.advancedAi.ollamaPull.installed": "Installiert", - "settings.advancedAi.ollamaPull.useModel": "Dieses Modell verwenden", - "settings.advancedAi.ollamaPull.batteryNote": "Eine Größe kleiner gewählt, um Akku zu sparen.", "settings.advancedAi.ollamaPull.tier.high-end": "High-End", - "settings.advancedAi.ollamaPull.tier.mid-range": "Mittelklasse", "settings.advancedAi.ollamaPull.tier.low-end": "Einsteiger", + "settings.advancedAi.ollamaPull.tier.mid-range": "Mittelklasse", + "settings.advancedAi.ollamaPull.useModel": "Dieses Modell verwenden", "settings.advancedAi.ragModeHint": "Der Hybrid-Modus verbindet Keyword-Suche mit semantischem Verständnis — ideal für die meisten Geschichten. Index nach großen Änderungen neu aufbauen.", "settings.advancedAi.ragModeHybrid": "Hybrid (semantisch + lexikalisch, empfohlen)", "settings.advancedAi.ragModeLabel": "Kontext-Abrufmodus", @@ -121,6 +122,7 @@ "settings.ai.creativity": "KI-Kreativitätsstufe", "settings.ai.creativityDescription": "Höhere Werte erzeugen unerwartetere Ergebnisse.", "settings.ai.customModel": "Benutzerdefiniertes Modell", + "settings.ai.downloadDesktopCta": "Desktop-App herunterladen", "settings.ai.fallbackNone": "Keiner", "settings.ai.fallbackStep1": "Erster Fallback", "settings.ai.fallbackStep2": "Zweiter Fallback", @@ -204,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Nicht verfügbar", "settings.ai.localBackendPreset": "Lokales Backend-Preset", "settings.ai.ollamaBrowserNote": "Ollama ist nur in der Desktop-App verfügbar. Die Browser-CSP blockiert direkte Verbindungen zu localhost.", - "settings.ai.ollamaHint": "Stellen Sie sicher, dass ollama serve läuft und CORS aktiviert ist.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama und lokale OpenAI-kompatible Server (LM Studio, vLLM) sind nur in der Desktop-App verfügbar. Browser blockieren direkte Verbindungen zu localhost (Content Security Policy und Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Desktop-App für lokale Server erforderlich", + "settings.ai.ollamaHint": "Stelle sicher, dass der Server läuft (z. B. ollama serve). Die Desktop-App verbindet sich direkt — kein CORS-Setup nötig.", "settings.ai.ollamaModelHint": "Modelle vom Server schnell auswählen — antippen zum Verwenden.", "settings.ai.ollamaServerUrl": "Ollama-Server-URL", "settings.ai.ollamaTauriBypass": "Desktop-Build: WorldScript spricht Ollama direkt an — keine Browser-CORS-Hürde.", @@ -236,6 +240,9 @@ "settings.ai.scanLocalPorts": "Gängige lokale Ports scannen", "settings.ai.scanNo": "keine Antwort", "settings.ai.scanOk": "erreichbar", + "settings.ai.scanStateHttp": "HTTP-Fehler", + "settings.ai.scanStateTimeout": "Zeitüberschreitung", + "settings.ai.scanUseUrl": "Diese URL übernehmen", "settings.ai.temperature.balanced": "1 – Ausgewogen", "settings.ai.temperature.creative": "2 – Kreativ", "settings.ai.temperature.precise": "0 – Präzise", @@ -435,24 +442,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Live-Vorschau", "settings.editor.title": "Editor-Einstellungen", - "settings.featureFlags.description": "Probiere Funktionen aus, an denen wir noch arbeiten. Dein Feedback formt, was als Nächstes erscheint.", - "settings.featureFlags.category.core": "Schreiben", "settings.featureFlags.category.ai": "KI", - "settings.featureFlags.category.pipeline": "Bearbeitungs-Pipeline", - "settings.featureFlags.category.personalization": "Personalisierung", "settings.featureFlags.category.analytics": "Analyse", - "settings.featureFlags.category.performance": "Leistung", - "settings.featureFlags.category.voice": "Sprachsteuerung", + "settings.featureFlags.category.core": "Schreiben", "settings.featureFlags.category.extensions": "Erweiterungen", - "settings.featureFlags.category.sync": "Synchronisierung", "settings.featureFlags.category.i18n": "Sprache & Layout", - "settings.featureFlags.dependency.requires": "Erfordert {{name}}", + "settings.featureFlags.category.performance": "Leistung", + "settings.featureFlags.category.personalization": "Personalisierung", + "settings.featureFlags.category.pipeline": "Bearbeitungs-Pipeline", + "settings.featureFlags.category.sync": "Synchronisierung", + "settings.featureFlags.category.voice": "Sprachsteuerung", "settings.featureFlags.dependency.desktopOnly": "Nur Desktop-App", - "settings.featureFlags.risk.high": "Kann erheblichen Arbeitsspeicher, GPU oder Token-Budget beanspruchen.", - "settings.featureFlags.resetToDefaults": "Auf Standard zurücksetzen", - "settings.featureFlags.resetTitle": "Experimentelle Funktionen zurücksetzen?", - "settings.featureFlags.resetConfirm": "Dadurch werden alle experimentellen Funktionen auf ihren Standardzustand (ein/aus) zurückgesetzt. Deine Projekte und Inhalte sind nicht betroffen.", - "settings.featureFlags.resetDone": "Experimentelle Funktionen auf Standard zurückgesetzt.", + "settings.featureFlags.dependency.requires": "Erfordert {{name}}", + "settings.featureFlags.description": "Probiere Funktionen aus, an denen wir noch arbeiten. Dein Feedback formt, was als Nächstes erscheint.", "settings.featureFlags.enableAdaptiveAiEngine": "Adaptiver KI-Motor (hardware-adaptive Backend-Auswahl)", "settings.featureFlags.enableAppHealthPanel": "App-Gesundheit (Über „Info“)", "settings.featureFlags.enableBinderResearch": "Recherche-Binder (Manuskript-Seitenleiste)", @@ -475,6 +477,11 @@ "settings.featureFlags.enableVoiceSupport": "Sprachbefehle & Diktat", "settings.featureFlags.enableVoiceWasm": "Sprach-WASM-Engine (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (typisierter Worker-Orchestrator — Phase 2)", + "settings.featureFlags.resetConfirm": "Dadurch werden alle experimentellen Funktionen auf ihren Standardzustand (ein/aus) zurückgesetzt. Deine Projekte und Inhalte sind nicht betroffen.", + "settings.featureFlags.resetDone": "Experimentelle Funktionen auf Standard zurückgesetzt.", + "settings.featureFlags.resetTitle": "Experimentelle Funktionen zurücksetzen?", + "settings.featureFlags.resetToDefaults": "Auf Standard zurücksetzen", + "settings.featureFlags.risk.high": "Kann erheblichen Arbeitsspeicher, GPU oder Token-Budget beanspruchen.", "settings.featureFlags.title": "Early-Access-Funktionen", "settings.font.custom": "Benutzerdefinierte Schriftart", "settings.font.mono": "Monospace", @@ -604,8 +611,8 @@ "settings.openRouter.modelFetch.loading": "Modellkatalog wird geladen …", "settings.openRouter.modelPlaceholder": "Modell auswählen oder suchen", "settings.openRouter.paidModelNote": "Kostenpflichtige Modelle benötigen Guthaben auf deinem OpenRouter-Konto.", - "settings.openRouter.policyBlocked.mode": "OpenRouter ist im KI-Modus „Lokal“ oder „Eco“ nicht verfügbar. Wechsle unter „KI & Modelle“ zu Hybrid oder Cloud, um es zu nutzen.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter ist blockiert, weil „Nur lokaler Speicher“ aktiviert ist. Deaktiviere es unter „Datenschutz & Daten“, um Cloud-KI zu erlauben.", + "settings.openRouter.policyBlocked.mode": "OpenRouter ist im KI-Modus „Lokal“ oder „Eco“ nicht verfügbar. Wechsle unter „KI & Modelle“ zu Hybrid oder Cloud, um es zu nutzen.", "settings.openRouter.preferredModel": "Bevorzugtes Modell", "settings.openRouter.resetCircuit": "Zurücksetzen", "settings.openRouter.resetCircuitAria": "OpenRouter-Schutzschalter zurücksetzen", @@ -737,8 +744,8 @@ "settings.voice.enableHint": "Aktiviert Sprachbefehle, Diktat und akustisches Feedback.", "settings.voice.enableLabel": "Sprachunterstützung aktivieren", "settings.voice.engine.auto": "Automatisch (empfohlen)", - "settings.voice.engine.wasm": "Lokales WASM-Modell (offline)", "settings.voice.engine.privacyNote": "Datenschutz: „Web Speech API“ sendet Audio an deinen Browser-Anbieter (Google, Apple oder Microsoft). „Lokales WASM-Modell“ läuft vollständig auf deinem Gerät. „Auto“ bevorzugt lokal und greift ggf. auf die Cloud zurück.", + "settings.voice.engine.wasm": "Lokales WASM-Modell (offline)", "settings.voice.engine.webSpeech": "Web Speech API (Cloud)", "settings.voice.feedbackLevel": "Audio-Feedback-Stufe", "settings.voice.intro": "Steuere WorldScript Studio mit deiner Stimme. Wähle unten eine Cloud- oder vollständig lokale Sprach-Engine.", @@ -780,6 +787,5 @@ "voice.modelDownload.error": "Download fehlgeschlagen: {{error}}", "voice.modelDownload.progress": "{{percent}}% abgeschlossen", "voice.modelDownload.retry": "Wiederholen", - "voice.modelDownload.title": "Sprachmodell-Download", - "settings.about.productName": "WorldScript Studio" + "voice.modelDownload.title": "Sprachmodell-Download" } diff --git a/locales/el/settings.json b/locales/el/settings.json index d79728ce..d5e71657 100644 --- a/locales/el/settings.json +++ b/locales/el/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "Επίπεδο δημιουργικότητας AI", "settings.ai.creativityDescription": "Οι υψηλότερες τιμές παράγουν περισσότερα απροσδόκητα αποτελέσματα.", "settings.ai.customModel": "Προσαρμοσμένο μοντέλο", + "settings.ai.downloadDesktopCta": "Λήψη της εφαρμογής επιφάνειας εργασίας", "settings.ai.fallbackNone": "Κανένας", "settings.ai.fallbackStep1": "Πρώτη εναλλακτική", "settings.ai.fallbackStep2": "Δεύτερη εναλλακτική", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Μη διαθέσιμο", "settings.ai.localBackendPreset": "Τοπική προεπιλογή υποστήριξης", "settings.ai.ollamaBrowserNote": "Το Olama είναι διαθέσιμο μόνο στην εφαρμογή για υπολογιστές. Η Πολιτική Ασφάλειας Περιεχομένου του προγράμματος περιήγησης αποκλείει τις άμεσες συνδέσεις με τον localhost.", - "settings.ai.ollamaHint": "Βεβαιωθείτε ότι η υπηρεσία ollama εκτελείται και ότι το CORS είναι ενεργοποιημένο.", + "settings.ai.ollamaDesktopOnlyBody": "Το Ollama και οι τοπικοί διακομιστές συμβατοί με OpenAI (LM Studio, vLLM) είναι διαθέσιμοι μόνο στην εφαρμογή επιφάνειας εργασίας. Τα προγράμματα περιήγησης αποκλείουν απευθείας συνδέσεις με το localhost (Content Security Policy και Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Απαιτείται εφαρμογή επιφάνειας εργασίας για τοπικούς διακομιστές", + "settings.ai.ollamaHint": "Βεβαιωθείτε ότι ο διακομιστής εκτελείται (π.χ. ollama serve). Η εφαρμογή επιφάνειας εργασίας συνδέεται απευθείας — δεν απαιτείται ρύθμιση CORS.", "settings.ai.ollamaModelHint": "Γρήγορη επιλογή μοντέλων που αναφέρονται από τον διακομιστή σας — πατήστε για χρήση.", "settings.ai.ollamaServerUrl": "Διεύθυνση URL διακομιστή Olama", "settings.ai.ollamaTauriBypass": "Κατασκευή επιφάνειας εργασίας: Το WorldScript καλεί απευθείας τον Ollama — χωρίς φραγμό CORS του προγράμματος περιήγησης.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Σάρωση κοινών τοπικών θυρών", "settings.ai.scanNo": "καμία απάντηση", "settings.ai.scanOk": "προσιτό", + "settings.ai.scanStateHttp": "σφάλμα HTTP", + "settings.ai.scanStateTimeout": "λήξη χρονικού ορίου", + "settings.ai.scanUseUrl": "Χρήση αυτού του URL", "settings.ai.temperature.balanced": "1 – Ισορροπημένο", "settings.ai.temperature.creative": "2 – Δημιουργικό", "settings.ai.temperature.precise": "0 – Ακριβές", diff --git a/locales/en/settings.json b/locales/en/settings.json index d30fb492..1560b6a5 100644 --- a/locales/en/settings.json +++ b/locales/en/settings.json @@ -13,6 +13,7 @@ "settings.about.githubDescription": "View source code, report issues, and contribute.", "settings.about.githubLabel": "Open-source on GitHub", "settings.about.liveDemo": "Try the live demo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Desktop runtime version", "settings.about.title": "About WorldScript Studio", "settings.about.versionLabel": "Version", @@ -63,16 +64,16 @@ "settings.advancedAi.model": "AI Model", "settings.advancedAi.modelDescription": "The AI model used for scene generation, analysis, and other AI-powered features. Model availability depends on your selected provider.", "settings.advancedAi.modelRecommendationsIntro": "Popular local checkpoints (verify names in your runtime):", - "settings.advancedAi.ollamaPull.recommendedFor": "Recommended for your device:", + "settings.advancedAi.ollamaPull.batteryNote": "Stepped down a size to save battery.", + "settings.advancedAi.ollamaPull.installed": "Installed", "settings.advancedAi.ollamaPull.pull": "Pull model", "settings.advancedAi.ollamaPull.pulling": "Downloading model…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recommended for your device:", "settings.advancedAi.ollamaPull.retry": "Retry", - "settings.advancedAi.ollamaPull.installed": "Installed", - "settings.advancedAi.ollamaPull.useModel": "Use this model", - "settings.advancedAi.ollamaPull.batteryNote": "Stepped down a size to save battery.", "settings.advancedAi.ollamaPull.tier.high-end": "High-end", - "settings.advancedAi.ollamaPull.tier.mid-range": "Mid-range", "settings.advancedAi.ollamaPull.tier.low-end": "Low-end", + "settings.advancedAi.ollamaPull.tier.mid-range": "Mid-range", + "settings.advancedAi.ollamaPull.useModel": "Use this model", "settings.advancedAi.ragModeHint": "Hybrid mode blends keyword matching with semantic understanding — best for most stories. Rebuild the index after large edits.", "settings.advancedAi.ragModeHybrid": "Hybrid (semantic + lexical, recommended)", "settings.advancedAi.ragModeLabel": "Context retrieval mode", @@ -82,85 +83,6 @@ "settings.advancedAi.temperature": "Temperature", "settings.advancedAi.temperatureDescription": "Controls randomness. Higher values produce more creative, unpredictable text; lower values make output more focused and deterministic.", "settings.advancedAi.title": "Advanced AI Settings", - "settings.aiMode.title": "AI Execution Mode", - "settings.aiMode.description": "Choose how the app processes AI requests. Cloud mode uses your API key for best quality, Local mode runs everything on your device for maximum privacy, and Hybrid mode automatically picks the best option.", - "settings.aiMode.hybrid": "Hybrid (Smart)", - "settings.aiMode.hybridDesc": "Automatically uses local models when preloaded, otherwise falls back to the cloud. Best of both worlds.", - "settings.aiMode.cloud": "Cloud", - "settings.aiMode.cloudDesc": "All AI requests are sent to the cloud provider (Gemini, OpenAI, etc.). Best quality, requires an API key and internet connection.", - "settings.aiMode.local": "Local", - "settings.aiMode.localDesc": "All AI runs on your device using local models. No data leaves the device. Works completely offline once models are preloaded.", - "settings.aiMode.eco": "Eco", - "settings.aiMode.ecoDesc": "Battery-saving mode for low-end or mobile devices. Uses only the small 0.5B text model and rule-based heuristics. No cloud, no heavy models.", - "settings.aiMode.activeLabel": "Active: {{mode}}", - "settings.aiMode.indicator.cloud": "Cloud", - "settings.aiMode.indicator.local": "Local", - "settings.aiMode.indicator.hybrid": "Hybrid", - "settings.aiMode.indicator.eco": "Eco", - "settings.aiMode.indicator.tooltip.cloud": "Cloud mode — all AI calls go to your cloud provider", - "settings.aiMode.indicator.tooltip.local": "Local mode — all AI runs on your device", - "settings.aiMode.indicator.tooltip.hybrid": "Hybrid mode — cloud first, local as offline fallback", - "settings.aiMode.indicator.tooltip.eco": "Eco mode — smallest local model, no cloud, battery-saving", - "settings.aiMode.indicator.orCircuitOpen": "OpenRouter paused (too many rate limits). Falling back to other providers.", - "settings.aiMode.indicatorAriaLabel": "Active AI mode", - "settings.aiMode.indicator.openRouter": "OpenRouter", - "settings.aiMode.indicator.openRouterFree": "OpenRouter Free", - "settings.aiMode.indicator.orShort": "OR ⚠", - "settings.aiMode.indicator.rpm": "{{count}}/20 RPM", - "settings.aiMode.hint.webgpuMissing": "WebGPU not detected — on-device models may run slowly or fall back to a smaller engine.", - "settings.aiMode.hint.cloudOffline": "You're offline — Cloud mode can't reach the AI provider. Reconnect or switch to Local/Eco.", - "settings.aiMode.hint.hybridOffline": "You're offline — Hybrid mode will use the on-device fallback until you reconnect.", - "settings.openRouter.title": "OpenRouter", - "settings.openRouter.description": "Use OpenRouter as a unified cloud gateway. Free-tier models (marked with :free) need no paid credits.", - "settings.openRouter.enabled": "Enable OpenRouter", - "settings.openRouter.enabledHint": "When enabled, OpenRouter is preferred for cloud AI calls unless the active mode forbids cloud.", - "settings.openRouter.apiKey": "API Key", - "settings.openRouter.apiKeyPlaceholder": "sk-or-v1-…", - "settings.openRouter.apiKeyHint": "Stored encrypted on this device.", - "settings.openRouter.apiKeyAriaLabel": "OpenRouter API key", - "settings.openRouter.keyStatus.set": "Key stored — enter a new key to replace it", - "settings.openRouter.keyStatus.unset": "No API key stored", - "settings.openRouter.keyStatus.saving": "Saving…", - "settings.openRouter.keyStatus.saved": "API key saved", - "settings.openRouter.keyStatus.removed": "API key removed", - "settings.openRouter.keyError.empty": "Please enter an OpenRouter API key", - "settings.openRouter.keyError.saveFailed": "Failed to save the API key", - "settings.openRouter.keyError.invalid": "The API key appears invalid", - "settings.openRouter.keyError.network": "Network error while validating the key", - "settings.openRouter.preferredModel": "Preferred Model", - "settings.openRouter.modelPlaceholder": "Select or search a model", - "settings.openRouter.modelAriaLabel": "Preferred OpenRouter model", - "settings.openRouter.customModelLabel": "Custom model…", - "settings.openRouter.customModelPlaceholder": "deepseek/deepseek-r1:free", - "settings.openRouter.customModelAriaLabel": "Custom model identifier", - "settings.openRouter.modelFetch.loading": "Loading model catalog…", - "settings.openRouter.modelFetch.failed": "Could not load model catalog", - "settings.openRouter.modelFetch.empty": "No models found", - "settings.openRouter.freeTierNote": "Free-tier models: 20 req/min, 50 req/day without credits", - "settings.openRouter.freeModel.deepseekR1": "DeepSeek R1 (free)", - "settings.openRouter.freeModel.llama3370b": "Llama 3.3 70B Instruct (free)", - "settings.openRouter.freeModel.qwen2572b": "Qwen 2.5 72B Instruct (free)", - "settings.openRouter.freeModel.gemma327b": "Gemma 3 27B IT (free)", - "settings.openRouter.freeModel.mistral7b": "Mistral 7B Instruct (free)", - "settings.openRouter.paidModelNote": "Paid models require credits on your OpenRouter account.", - "settings.openRouter.policyBlocked.mode": "OpenRouter is unavailable while the AI mode is Local or Eco. Switch to Hybrid or Cloud in AI & Models to use it.", - "settings.openRouter.policyBlocked.localOnly": "OpenRouter is blocked because “Local storage only” is on. Turn it off in Privacy & Data to allow cloud AI.", - "settings.openRouter.getKeyLink": "Get a free API key at openrouter.ai/keys", - "settings.openRouter.testConnection": "Test connection", - "settings.openRouter.testConnectionOk": "Connection successful", - "settings.openRouter.testConnectionFailed": "Connection failed", - "settings.openRouter.saveKey": "Save", - "settings.openRouter.clearKey": "Remove", - "settings.openRouter.circuitBreaker": "Circuit breaker:", - "settings.openRouter.circuitOpen": "Open (paused 5 min)", - "settings.openRouter.circuitClosed": "Closed (healthy)", - "settings.openRouter.resetCircuit": "Reset", - "settings.openRouter.resetCircuitAria": "Reset OpenRouter circuit breaker", - "settings.openRouter.rpmLabel": "Requests / min (last 60 s)", - "settings.openRouter.modeWarning.local": "OpenRouter is disabled while AI mode is set to local-only.", - "settings.openRouter.modeWarning.offline": "OpenRouter is paused because the device is offline.", - "settings.openRouter.errors.generic": "An unexpected OpenRouter error occurred", - "settings.categories.openrouter": "OpenRouter", "settings.advancedAi.topP": "Top P", "settings.advancedAi.topPDescription": "Nucleus sampling threshold. Only tokens whose cumulative probability reaches this value are considered. Lower values = more focused output.", "settings.advancedEditor.autoComplete": "Auto-Complete Suggestions", @@ -200,6 +122,7 @@ "settings.ai.creativity": "AI Creativity Level", "settings.ai.creativityDescription": "Higher values produce more unexpected results.", "settings.ai.customModel": "Custom Model", + "settings.ai.downloadDesktopCta": "Download the desktop app", "settings.ai.fallbackNone": "None", "settings.ai.fallbackStep1": "First fallback", "settings.ai.fallbackStep2": "Second fallback", @@ -228,15 +151,64 @@ "settings.ai.loadModels": "Load models", "settings.ai.localAi.cancelAriaLabel": "Cancel model download", "settings.ai.localAi.cancelButton": "Cancel", + "settings.ai.localAi.clearBusy": "Local AI is busy right now — try clearing again once it finishes.", + "settings.ai.localAi.clearButton": "Clear Local Models", + "settings.ai.localAi.clearCancel": "Cancel", + "settings.ai.localAi.clearConfirm": "Delete all downloaded local models? They will re-download the next time you use local AI.", + "settings.ai.localAi.clearConfirmYes": "Delete models", + "settings.ai.localAi.clearFailed": "Could not clear local models. Please try again.", + "settings.ai.localAi.clearedAnnounce": "Cleared {{count}} local model cache(s)", + "settings.ai.localAi.clearingButton": "Clearing…", + "settings.ai.localAi.detecting": "Detecting…", + "settings.ai.localAi.deviceClassLabel": "Device class", + "settings.ai.localAi.docsLink": "Local AI setup & troubleshooting", + "settings.ai.localAi.downloadButton": "Download", "settings.ai.localAi.downloadCancelled": "Download cancelled", "settings.ai.localAi.downloadEta": "approx. {{seconds}}s remaining", + "settings.ai.localAi.downloadFailed": "Download failed. Please try again.", "settings.ai.localAi.downloadTitle": "Downloading AI model…", "settings.ai.localAi.downloadedLabel": "downloaded", + "settings.ai.localAi.downloadingButton": "Downloading…", + "settings.ai.localAi.fallbackIntro": "When a layer is unavailable, the Co-Pilot automatically tries the next one:", + "settings.ai.localAi.fallbackLayer1": "WebGPU (WebLLM) — fastest and highest quality; needs a capable GPU.", + "settings.ai.localAi.fallbackLayer2": "WASM (ONNX) — runs on the CPU when no GPU is available.", + "settings.ai.localAi.fallbackLayer3": "Transformers.js — lightweight last-resort generator.", + "settings.ai.localAi.fallbackLayer4": "Heuristic — always-available offline stub when no model can run.", + "settings.ai.localAi.fallbackTitle": "Fallback chain", + "settings.ai.localAi.modelLabel.gemma3_1b": "Gemma 3 1B (~0.8 GB)", + "settings.ai.localAi.modelLabel.gemma3_4b": "Gemma 3 4B (~4.9 GB)", + "settings.ai.localAi.modelLabel.llama32_1b": "Llama 3.2 1B (fast, ~0.7 GB)", + "settings.ai.localAi.modelLabel.llama32_3b": "Llama 3.2 3B (~1.8 GB)", + "settings.ai.localAi.modelLabel.llama33_70b": "Llama 3.3 70B (high-end, ~35 GB)", + "settings.ai.localAi.modelLabel.phi4mini": "Phi-4 Mini 3.8B (~2.3 GB)", + "settings.ai.localAi.modelLabel.qwen25_05b": "Qwen 2.5 0.5B (eco, ~0.4 GB)", + "settings.ai.localAi.modelReadyAnnounce": "{{model}} is ready for offline use", + "settings.ai.localAi.modelsDescription": "Download a model to use it offline. Larger models are higher quality but need more storage and a capable GPU.", + "settings.ai.localAi.modelsTitle": "Models", + "settings.ai.localAi.onboardingHint": "No local model downloaded yet. Download one below to enable offline AI — the first download may take a few minutes.", + "settings.ai.localAi.perfNoData": "Download and run a model to measure throughput.", + "settings.ai.localAi.perfThroughput": "Last local run: {{tps}} tokens/sec", "settings.ai.localAi.progressAriaLabel": "Model download progress", + "settings.ai.localAi.readyBadge": "Ready", + "settings.ai.localAi.recommendedModel": "Recommended for your device: {{model}}", + "settings.ai.localAi.requiresGpuNote": "Without WebGPU, models run on a slower CPU/WASM fallback or download may be unavailable.", "settings.ai.localAi.retryButton": "Retry", + "settings.ai.localAi.sectionDescription": "Run inference on your device. No data leaves the browser. Capability, downloads, and storage are managed here.", + "settings.ai.localAi.sectionTitle": "Local AI", + "settings.ai.localAi.sizeWarning": "Needs ~{{size}} MB; only {{free}} MB free", + "settings.ai.localAi.storageAriaLabel": "Local storage usage", + "settings.ai.localAi.storageModelsCached": "{{count}} local model cache(s) on disk", + "settings.ai.localAi.storageTitle": "Storage", + "settings.ai.localAi.storageUnsupported": "Storage estimates are not available in this browser.", + "settings.ai.localAi.storageUsage": "{{used}} MB of {{quota}} MB used ({{percent}}%)", + "settings.ai.localAi.webgpuAvailable": "Available", + "settings.ai.localAi.webgpuLabel": "WebGPU", + "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "Local backend preset", "settings.ai.ollamaBrowserNote": "Ollama is only available in the desktop app. The browser's Content Security Policy blocks direct connections to localhost.", - "settings.ai.ollamaHint": "Make sure ollama serve is running and CORS is enabled.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama and local OpenAI-compatible servers (LM Studio, vLLM) are only available in the desktop app. Browsers block direct connections to localhost (Content Security Policy and Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Desktop app required for local servers", + "settings.ai.ollamaHint": "Make sure the server is running (e.g. ollama serve). The desktop app connects directly — no CORS setup needed.", "settings.ai.ollamaModelHint": "Quick-select models reported by your server — tap to use.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Desktop build: WorldScript calls Ollama directly — no browser CORS barrier.", @@ -268,6 +240,9 @@ "settings.ai.scanLocalPorts": "Scan common local ports", "settings.ai.scanNo": "no response", "settings.ai.scanOk": "reachable", + "settings.ai.scanStateHttp": "HTTP error", + "settings.ai.scanStateTimeout": "timeout", + "settings.ai.scanUseUrl": "Use this URL", "settings.ai.temperature.balanced": "1 – Balanced", "settings.ai.temperature.creative": "2 – Creative", "settings.ai.temperature.precise": "0 – Precise", @@ -291,6 +266,34 @@ "settings.ai.webllm.tabLeaderNote": "Only one browser tab runs local inference at a time.", "settings.ai.webllm.vramLabel": "VRAM tier", "settings.ai.webllmHint": "Runs entirely in your browser via WebGPU (optional packages). Large model downloads on first use; use Ollama on desktop for heavier models.", + "settings.aiMode.activeLabel": "Active: {{mode}}", + "settings.aiMode.cloud": "Cloud", + "settings.aiMode.cloudDesc": "All AI requests are sent to the cloud provider (Gemini, OpenAI, etc.). Best quality, requires an API key and internet connection.", + "settings.aiMode.description": "Choose how the app processes AI requests. Cloud mode uses your API key for best quality, Local mode runs everything on your device for maximum privacy, and Hybrid mode automatically picks the best option.", + "settings.aiMode.eco": "Eco", + "settings.aiMode.ecoDesc": "Battery-saving mode for low-end or mobile devices. Uses only the small 0.5B text model and rule-based heuristics. No cloud, no heavy models.", + "settings.aiMode.hint.cloudOffline": "You're offline — Cloud mode can't reach the AI provider. Reconnect or switch to Local/Eco.", + "settings.aiMode.hint.hybridOffline": "You're offline — Hybrid mode will use the on-device fallback until you reconnect.", + "settings.aiMode.hint.webgpuMissing": "WebGPU not detected — on-device models may run slowly or fall back to a smaller engine.", + "settings.aiMode.hybrid": "Hybrid (Smart)", + "settings.aiMode.hybridDesc": "Automatically uses local models when preloaded, otherwise falls back to the cloud. Best of both worlds.", + "settings.aiMode.indicator.cloud": "Cloud", + "settings.aiMode.indicator.eco": "Eco", + "settings.aiMode.indicator.hybrid": "Hybrid", + "settings.aiMode.indicator.local": "Local", + "settings.aiMode.indicator.openRouter": "OpenRouter", + "settings.aiMode.indicator.openRouterFree": "OpenRouter Free", + "settings.aiMode.indicator.orCircuitOpen": "OpenRouter paused (too many rate limits). Falling back to other providers.", + "settings.aiMode.indicator.orShort": "OR ⚠", + "settings.aiMode.indicator.rpm": "{{count}}/20 RPM", + "settings.aiMode.indicator.tooltip.cloud": "Cloud mode — all AI calls go to your cloud provider", + "settings.aiMode.indicator.tooltip.eco": "Eco mode — smallest local model, no cloud, battery-saving", + "settings.aiMode.indicator.tooltip.hybrid": "Hybrid mode — cloud first, local as offline fallback", + "settings.aiMode.indicator.tooltip.local": "Local mode — all AI runs on your device", + "settings.aiMode.indicatorAriaLabel": "Active AI mode", + "settings.aiMode.local": "Local", + "settings.aiMode.localDesc": "All AI runs on your device using local models. No data leaves the device. Works completely offline once models are preloaded.", + "settings.aiMode.title": "AI Execution Mode", "settings.apiKey.configured": "API Key Configured", "settings.apiKey.encryptedNote": "Encrypted and stored in IndexedDB", "settings.apiKey.errorEmpty": "Please enter an API key", @@ -341,7 +344,9 @@ "settings.categories.general": "General", "settings.categories.guide": "Settings guide", "settings.categories.integrations": "Integrations", + "settings.categories.localAi": "Local AI", "settings.categories.loraAdapters": "LoRA Adapters", + "settings.categories.openrouter": "OpenRouter", "settings.categories.plugins": "Plugins", "settings.categories.privacy": "Privacy & Security", "settings.categories.privacyData": "Privacy & Data", @@ -437,24 +442,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Live Preview", "settings.editor.title": "Editor Preferences", - "settings.featureFlags.description": "Try features we're still refining. Your feedback shapes what ships next.", - "settings.featureFlags.category.core": "Writing", "settings.featureFlags.category.ai": "AI", - "settings.featureFlags.category.pipeline": "Editing Pipeline", - "settings.featureFlags.category.personalization": "Personalization", "settings.featureFlags.category.analytics": "Analytics", - "settings.featureFlags.category.performance": "Performance", - "settings.featureFlags.category.voice": "Voice", + "settings.featureFlags.category.core": "Writing", "settings.featureFlags.category.extensions": "Extensions", - "settings.featureFlags.category.sync": "Sync", "settings.featureFlags.category.i18n": "Language & Layout", - "settings.featureFlags.dependency.requires": "Requires {{name}}", + "settings.featureFlags.category.performance": "Performance", + "settings.featureFlags.category.personalization": "Personalization", + "settings.featureFlags.category.pipeline": "Editing Pipeline", + "settings.featureFlags.category.sync": "Sync", + "settings.featureFlags.category.voice": "Voice", "settings.featureFlags.dependency.desktopOnly": "Desktop app only", - "settings.featureFlags.risk.high": "May use significant memory, GPU, or token budget.", - "settings.featureFlags.resetToDefaults": "Reset to defaults", - "settings.featureFlags.resetTitle": "Reset experimental features?", - "settings.featureFlags.resetConfirm": "This restores every experimental feature to its default on/off state. Your projects and content are not affected.", - "settings.featureFlags.resetDone": "Experimental features reset to defaults.", + "settings.featureFlags.dependency.requires": "Requires {{name}}", + "settings.featureFlags.description": "Try features we're still refining. Your feedback shapes what ships next.", "settings.featureFlags.enableAdaptiveAiEngine": "Adaptive AI engine (hardware-aware backend selection)", "settings.featureFlags.enableAppHealthPanel": "App health snapshot (About)", "settings.featureFlags.enableBinderResearch": "Research binder (Manuscript sidebar)", @@ -462,6 +462,7 @@ "settings.featureFlags.enableCompileWizard": "Compile wizard (Export)", "settings.featureFlags.enableComputeShaders": "WebGPU compute shaders (GPU-accelerated RAG & attention)", "settings.featureFlags.enableDuckDbAnalytics": "Advanced analytics (fast story database)", + "settings.featureFlags.enableGlobalCopilot": "Global AI Copilot (beginner-friendly in-app live assistant)", "settings.featureFlags.enableIdbAtRestEncryption": "IDB at-rest encryption (AES-256-GCM) — enable via Settings › Privacy", "settings.featureFlags.enableLocalFirstSync": "Local-First sync (shadow — experimental)", "settings.featureFlags.enableLoraAdapters": "LoRA adapter inference (experimental)", @@ -471,12 +472,16 @@ "settings.featureFlags.enableProForge": "ProForge Pipeline (8-stage agentic editing)", "settings.featureFlags.enableProjectHealthScore": "Project health score (Dashboard)", "settings.featureFlags.enableRtlLayout": "RTL layout (experimental)", - "settings.featureFlags.enableGlobalCopilot": "Global AI Copilot (beginner-friendly in-app live assistant)", "settings.featureFlags.enableRustCompute": "Rust Compute (Tauri TaskSupervisor offloading — Phase 2)", "settings.featureFlags.enableStoryBibleAdvanced": "Story Bible advanced (graph + hints in Codex)", "settings.featureFlags.enableVoiceSupport": "Voice commands & dictation", "settings.featureFlags.enableVoiceWasm": "Voice WASM engine (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (typed worker orchestration — Phase 2)", + "settings.featureFlags.resetConfirm": "This restores every experimental feature to its default on/off state. Your projects and content are not affected.", + "settings.featureFlags.resetDone": "Experimental features reset to defaults.", + "settings.featureFlags.resetTitle": "Reset experimental features?", + "settings.featureFlags.resetToDefaults": "Reset to defaults", + "settings.featureFlags.risk.high": "May use significant memory, GPU, or token budget.", "settings.featureFlags.title": "Early Access Features", "settings.font.custom": "Custom Font", "settings.font.mono": "Monospace", @@ -511,6 +516,8 @@ "settings.guide.integrations.desc": "LanguageTool and external sync.", "settings.guide.integrations.title": "Integrations", "settings.guide.intro": "Overview of every settings category. Use search at the top of Settings to jump quickly.", + "settings.guide.localAi.desc": "Run the AI on your device — check capability, download models, manage storage, and review the offline fallback chain.", + "settings.guide.localAi.title": "Local AI", "settings.guide.loraAdapters.desc": "Manage local LoRA adapters that teach a model your writing voice.", "settings.guide.loraAdapters.title": "Fine-Tuning (LoRA)", "settings.guide.notifications.desc": "Reminders and desktop alerts.", @@ -553,8 +560,8 @@ "settings.language.hebrew": "Hebrew (beta)", "settings.language.italian": "Italian", "settings.language.japanese": "Japanese (beta)", - "settings.language.spanish": "Spanish", "settings.language.portuguese": "Portuguese (beta)", + "settings.language.spanish": "Spanish", "settings.language.title": "Language & Region", "settings.loraAdapters.deleteBtn": "Delete", "settings.loraAdapters.description": "Load LoRA fine-tuning adapters for local WebLLM models. Adapters are stored in your browser and never sent to the cloud.", @@ -565,6 +572,56 @@ "settings.loraAdapters.title": "LoRA Adapters", "settings.loraAdapters.uploadBtn": "Upload adapter (.safetensors / .bin)", "settings.loraAdapters.uploadError": "Failed to load adapter. The file may be invalid or too large.", + "settings.openRouter.apiKey": "API Key", + "settings.openRouter.apiKeyAriaLabel": "OpenRouter API key", + "settings.openRouter.apiKeyHint": "Stored encrypted on this device.", + "settings.openRouter.apiKeyPlaceholder": "sk-or-v1-…", + "settings.openRouter.circuitBreaker": "Circuit breaker:", + "settings.openRouter.circuitClosed": "Closed (healthy)", + "settings.openRouter.circuitOpen": "Open (paused 5 min)", + "settings.openRouter.clearKey": "Remove", + "settings.openRouter.customModelAriaLabel": "Custom model identifier", + "settings.openRouter.customModelLabel": "Custom model…", + "settings.openRouter.customModelPlaceholder": "deepseek/deepseek-r1:free", + "settings.openRouter.description": "Use OpenRouter as a unified cloud gateway. Free-tier models (marked with :free) need no paid credits.", + "settings.openRouter.enabled": "Enable OpenRouter", + "settings.openRouter.enabledHint": "When enabled, OpenRouter is preferred for cloud AI calls unless the active mode forbids cloud.", + "settings.openRouter.errors.generic": "An unexpected OpenRouter error occurred", + "settings.openRouter.freeModel.deepseekR1": "DeepSeek R1 (free)", + "settings.openRouter.freeModel.gemma327b": "Gemma 3 27B IT (free)", + "settings.openRouter.freeModel.llama3370b": "Llama 3.3 70B Instruct (free)", + "settings.openRouter.freeModel.mistral7b": "Mistral 7B Instruct (free)", + "settings.openRouter.freeModel.qwen2572b": "Qwen 2.5 72B Instruct (free)", + "settings.openRouter.freeTierNote": "Free-tier models: 20 req/min, 50 req/day without credits", + "settings.openRouter.getKeyLink": "Get a free API key at openrouter.ai/keys", + "settings.openRouter.keyError.empty": "Please enter an OpenRouter API key", + "settings.openRouter.keyError.invalid": "The API key appears invalid", + "settings.openRouter.keyError.network": "Network error while validating the key", + "settings.openRouter.keyError.saveFailed": "Failed to save the API key", + "settings.openRouter.keyStatus.removed": "API key removed", + "settings.openRouter.keyStatus.saved": "API key saved", + "settings.openRouter.keyStatus.saving": "Saving…", + "settings.openRouter.keyStatus.set": "Key stored — enter a new key to replace it", + "settings.openRouter.keyStatus.unset": "No API key stored", + "settings.openRouter.modeWarning.local": "OpenRouter is disabled while AI mode is set to local-only.", + "settings.openRouter.modeWarning.offline": "OpenRouter is paused because the device is offline.", + "settings.openRouter.modelAriaLabel": "Preferred OpenRouter model", + "settings.openRouter.modelFetch.empty": "No models found", + "settings.openRouter.modelFetch.failed": "Could not load model catalog", + "settings.openRouter.modelFetch.loading": "Loading model catalog…", + "settings.openRouter.modelPlaceholder": "Select or search a model", + "settings.openRouter.paidModelNote": "Paid models require credits on your OpenRouter account.", + "settings.openRouter.policyBlocked.localOnly": "OpenRouter is blocked because “Local storage only” is on. Turn it off in Privacy & Data to allow cloud AI.", + "settings.openRouter.policyBlocked.mode": "OpenRouter is unavailable while the AI mode is Local or Eco. Switch to Hybrid or Cloud in AI & Models to use it.", + "settings.openRouter.preferredModel": "Preferred Model", + "settings.openRouter.resetCircuit": "Reset", + "settings.openRouter.resetCircuitAria": "Reset OpenRouter circuit breaker", + "settings.openRouter.rpmLabel": "Requests / min (last 60 s)", + "settings.openRouter.saveKey": "Save", + "settings.openRouter.testConnection": "Test connection", + "settings.openRouter.testConnectionFailed": "Connection failed", + "settings.openRouter.testConnectionOk": "Connection successful", + "settings.openRouter.title": "OpenRouter", "settings.overview.openGuide": "Full settings guide", "settings.overview.title": "Quick links", "settings.plugins.description": "Manage WorldScript Studio extension plugins. Plugins run in a sandboxed API layer and can only access the permissions they declare.", @@ -606,11 +663,11 @@ "settings.privacy.encryptionUnlockButton": "Unlock", "settings.privacy.encryptionWarning": "If you forget your passphrase, your data cannot be recovered.", "settings.privacy.encryptionWrongPassphrase": "Wrong passphrase — decryption failed", + "settings.privacy.euDataResidency": "EU Data Residency", + "settings.privacy.euDataResidencyHint": "Keep all data within European Union servers where applicable.", "settings.privacy.localStorageOnly": "Local Storage Only", "settings.privacy.migrationComplete": "All data encrypted successfully", "settings.privacy.migrationProgress": "Encrypting existing data…", - "settings.privacy.euDataResidency": "EU Data Residency", - "settings.privacy.euDataResidencyHint": "Keep all data within European Union servers where applicable.", "settings.privacy.title": "Privacy & Security", "settings.projectAi.activeIndicator": "Project AI active", "settings.projectAi.category": "Project AI", @@ -681,8 +738,15 @@ "settings.voice.autoPunctuationHint": "Automatically add periods and commas while dictating.", "settings.voice.cloudFallback": "Allow Cloud STT Fallback", "settings.voice.cloudFallbackHint": "When local speech recognition is unavailable, send audio to cloud providers. Requires internet.", + "settings.voice.downloadModels": "Download Models", + "settings.voice.downloadSttModel": "Download STT (Whisper)", + "settings.voice.downloadTtsModel": "Download TTS (Kokoro)", "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", + "settings.voice.engine.auto": "Auto (recommended)", + "settings.voice.engine.privacyNote": "Privacy: ‘Web Speech API’ sends audio to your browser vendor (Google, Apple, or Microsoft). ‘Local WASM model’ runs fully on your device. ‘Auto’ prefers on-device and may fall back to cloud.", + "settings.voice.engine.wasm": "Local WASM model (offline)", + "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Control WorldScript Studio with your voice. Choose a cloud or fully on-device speech engine below.", "settings.voice.level.minimal": "Minimal — errors only", @@ -697,89 +761,31 @@ "settings.voice.privacy.consentDecline": "Decline", "settings.voice.privacy.consentTitle": "Web Speech Consent", "settings.voice.privacy.revokeConsent": "Revoke Consent", + "settings.voice.privacy.revokeConsentHint": "Removes your Web Speech consent. Voice will fall back to local WASM or be disabled.", "settings.voice.privacy.statusExternal": "External", "settings.voice.privacy.statusLocal": "Local", "settings.voice.privacyNotice": "By default, the Web Speech engine sends your audio to Google or Microsoft for transcription. Switch to the on-device (WASM) engine to keep all audio on your device.", + "settings.voice.pttHint": "Push-to-Talk shortcut: Ctrl+Shift+V (Windows/Linux) or ⌘+Shift+V (Mac). Hold to record.", + "settings.voice.speechRate": "Speech Rate", + "settings.voice.speechRateHint": "How fast the text-to-speech voice speaks. 1.0 = normal speed.", + "settings.voice.speechVolume": "Speech Volume", + "settings.voice.speechVolumeHint": "Volume of the text-to-speech voice. Does not affect microphone input.", + "settings.voice.sttEngine": "Speech Recognition (STT) Engine", + "settings.voice.sttEngineHint": "Choose the engine that converts your speech to text. 'Auto' picks the best available option.", "settings.voice.title": "Voice Full Support", + "settings.voice.ttsEngine": "Text-to-Speech (TTS) Engine", + "settings.voice.ttsEngineHint": "Choose the voice that reads responses aloud. 'Auto' picks the best available option.", "settings.voice.ttsMuted": "Mute All Speech Output", "settings.voice.ttsMutedHint": "Disable text-to-speech while keeping visual indicators.", + "settings.voice.wakeWordPhrase": "Wake Word Phrase", + "settings.voice.wakeWordPhraseHint": "The phrase you say to activate voice commands hands-free.", + "settings.voice.wasmModels": "WASM Voice Models", + "settings.voice.wasmModelsNotReady": "Whisper STT (~42 MB) and Kokoro TTS (~15 MB) models not downloaded", + "settings.voice.wasmModelsReady": "Downloaded and ready for local voice processing", "voice.modelDownload.cancel": "Cancel", "voice.modelDownload.description": "Downloading {{model}} model ({{size}} MB). This enables local voice processing without cloud routing.", "voice.modelDownload.error": "Download failed: {{error}}", "voice.modelDownload.progress": "{{percent}}% complete", "voice.modelDownload.retry": "Retry", - "voice.modelDownload.title": "Voice Model Download", - "settings.voice.wasmModels": "WASM Voice Models", - "settings.voice.wasmModelsReady": "Downloaded and ready for local voice processing", - "settings.voice.wasmModelsNotReady": "Whisper STT (~42 MB) and Kokoro TTS (~15 MB) models not downloaded", - "settings.voice.downloadModels": "Download Models", - "settings.voice.downloadSttModel": "Download STT (Whisper)", - "settings.voice.downloadTtsModel": "Download TTS (Kokoro)", - "settings.voice.sttEngine": "Speech Recognition (STT) Engine", - "settings.voice.sttEngineHint": "Choose the engine that converts your speech to text. 'Auto' picks the best available option.", - "settings.voice.ttsEngine": "Text-to-Speech (TTS) Engine", - "settings.voice.ttsEngineHint": "Choose the voice that reads responses aloud. 'Auto' picks the best available option.", - "settings.voice.engine.auto": "Auto (recommended)", - "settings.voice.engine.webSpeech": "Web Speech API (cloud)", - "settings.voice.engine.wasm": "Local WASM model (offline)", - "settings.voice.engine.privacyNote": "Privacy: ‘Web Speech API’ sends audio to your browser vendor (Google, Apple, or Microsoft). ‘Local WASM model’ runs fully on your device. ‘Auto’ prefers on-device and may fall back to cloud.", - "settings.voice.speechRate": "Speech Rate", - "settings.voice.speechRateHint": "How fast the text-to-speech voice speaks. 1.0 = normal speed.", - "settings.voice.speechVolume": "Speech Volume", - "settings.voice.speechVolumeHint": "Volume of the text-to-speech voice. Does not affect microphone input.", - "settings.voice.wakeWordPhrase": "Wake Word Phrase", - "settings.voice.wakeWordPhraseHint": "The phrase you say to activate voice commands hands-free.", - "settings.voice.pttHint": "Push-to-Talk shortcut: Ctrl+Shift+V (Windows/Linux) or ⌘+Shift+V (Mac). Hold to record.", - "settings.voice.privacy.revokeConsentHint": "Removes your Web Speech consent. Voice will fall back to local WASM or be disabled.", - "settings.categories.localAi": "Local AI", - "settings.guide.localAi.title": "Local AI", - "settings.guide.localAi.desc": "Run the AI on your device — check capability, download models, manage storage, and review the offline fallback chain.", - "settings.ai.localAi.sectionTitle": "Local AI", - "settings.ai.localAi.sectionDescription": "Run inference on your device. No data leaves the browser. Capability, downloads, and storage are managed here.", - "settings.ai.localAi.webgpuLabel": "WebGPU", - "settings.ai.localAi.webgpuAvailable": "Available", - "settings.ai.localAi.webgpuUnavailable": "Not available", - "settings.ai.localAi.deviceClassLabel": "Device class", - "settings.ai.localAi.recommendedModel": "Recommended for your device: {{model}}", - "settings.ai.localAi.onboardingHint": "No local model downloaded yet. Download one below to enable offline AI — the first download may take a few minutes.", - "settings.ai.localAi.modelsTitle": "Models", - "settings.ai.localAi.modelsDescription": "Download a model to use it offline. Larger models are higher quality but need more storage and a capable GPU.", - "settings.ai.localAi.downloadButton": "Download", - "settings.ai.localAi.downloadingButton": "Downloading…", - "settings.ai.localAi.readyBadge": "Ready", - "settings.ai.localAi.sizeWarning": "Needs ~{{size}} MB; only {{free}} MB free", - "settings.ai.localAi.modelReadyAnnounce": "{{model}} is ready for offline use", - "settings.ai.localAi.requiresGpuNote": "Without WebGPU, models run on a slower CPU/WASM fallback or download may be unavailable.", - "settings.ai.localAi.storageTitle": "Storage", - "settings.ai.localAi.storageUsage": "{{used}} MB of {{quota}} MB used ({{percent}}%)", - "settings.ai.localAi.storageModelsCached": "{{count}} local model cache(s) on disk", - "settings.ai.localAi.storageUnsupported": "Storage estimates are not available in this browser.", - "settings.ai.localAi.storageAriaLabel": "Local storage usage", - "settings.ai.localAi.clearButton": "Clear Local Models", - "settings.ai.localAi.clearingButton": "Clearing…", - "settings.ai.localAi.clearConfirm": "Delete all downloaded local models? They will re-download the next time you use local AI.", - "settings.ai.localAi.clearConfirmYes": "Delete models", - "settings.ai.localAi.clearCancel": "Cancel", - "settings.ai.localAi.clearedAnnounce": "Cleared {{count}} local model cache(s)", - "settings.ai.localAi.fallbackTitle": "Fallback chain", - "settings.ai.localAi.fallbackIntro": "When a layer is unavailable, the Co-Pilot automatically tries the next one:", - "settings.ai.localAi.fallbackLayer1": "WebGPU (WebLLM) — fastest and highest quality; needs a capable GPU.", - "settings.ai.localAi.fallbackLayer2": "WASM (ONNX) — runs on the CPU when no GPU is available.", - "settings.ai.localAi.fallbackLayer3": "Transformers.js — lightweight last-resort generator.", - "settings.ai.localAi.fallbackLayer4": "Heuristic — always-available offline stub when no model can run.", - "settings.ai.localAi.perfThroughput": "Last local run: {{tps}} tokens/sec", - "settings.ai.localAi.perfNoData": "Download and run a model to measure throughput.", - "settings.ai.localAi.docsLink": "Local AI setup & troubleshooting", - "settings.ai.localAi.detecting": "Detecting…", - "settings.ai.localAi.clearBusy": "Local AI is busy right now — try clearing again once it finishes.", - "settings.ai.localAi.downloadFailed": "Download failed. Please try again.", - "settings.ai.localAi.clearFailed": "Could not clear local models. Please try again.", - "settings.ai.localAi.modelLabel.qwen25_05b": "Qwen 2.5 0.5B (eco, ~0.4 GB)", - "settings.ai.localAi.modelLabel.llama32_1b": "Llama 3.2 1B (fast, ~0.7 GB)", - "settings.ai.localAi.modelLabel.llama32_3b": "Llama 3.2 3B (~1.8 GB)", - "settings.ai.localAi.modelLabel.phi4mini": "Phi-4 Mini 3.8B (~2.3 GB)", - "settings.ai.localAi.modelLabel.gemma3_1b": "Gemma 3 1B (~0.8 GB)", - "settings.ai.localAi.modelLabel.gemma3_4b": "Gemma 3 4B (~4.9 GB)", - "settings.ai.localAi.modelLabel.llama33_70b": "Llama 3.3 70B (high-end, ~35 GB)", - "settings.about.productName": "WorldScript Studio" + "voice.modelDownload.title": "Voice Model Download" } diff --git a/locales/es/settings.json b/locales/es/settings.json index 3ebcc990..50c3252a 100644 --- a/locales/es/settings.json +++ b/locales/es/settings.json @@ -13,6 +13,7 @@ "settings.about.githubDescription": "Ver el código fuente, reportar errores y contribuir.", "settings.about.githubLabel": "Código abierto en GitHub", "settings.about.liveDemo": "Probar la demo en vivo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Versión del runtime de escritorio", "settings.about.title": "Acerca de WorldScript Studio", "settings.about.versionLabel": "Versión", @@ -63,16 +64,16 @@ "settings.advancedAi.model": "Modelo de IA", "settings.advancedAi.modelDescription": "El modelo de IA usado para generación de escenas, análisis y otras funciones. La disponibilidad depende del proveedor seleccionado.", "settings.advancedAi.modelRecommendationsIntro": "Puntos de control locales populares (verifica los nombres en tu entorno de ejecución):", - "settings.advancedAi.ollamaPull.recommendedFor": "Recomendado para tu dispositivo:", + "settings.advancedAi.ollamaPull.batteryNote": "Se eligió un tamaño menor para ahorrar batería.", + "settings.advancedAi.ollamaPull.installed": "Instalado", "settings.advancedAi.ollamaPull.pull": "Descargar modelo", "settings.advancedAi.ollamaPull.pulling": "Descargando modelo…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recomendado para tu dispositivo:", "settings.advancedAi.ollamaPull.retry": "Reintentar", - "settings.advancedAi.ollamaPull.installed": "Instalado", - "settings.advancedAi.ollamaPull.useModel": "Usar este modelo", - "settings.advancedAi.ollamaPull.batteryNote": "Se eligió un tamaño menor para ahorrar batería.", "settings.advancedAi.ollamaPull.tier.high-end": "Gama alta", - "settings.advancedAi.ollamaPull.tier.mid-range": "Gama media", "settings.advancedAi.ollamaPull.tier.low-end": "Gama baja", + "settings.advancedAi.ollamaPull.tier.mid-range": "Gama media", + "settings.advancedAi.ollamaPull.useModel": "Usar este modelo", "settings.advancedAi.ragModeHint": "El modo híbrido combina búsqueda por palabras clave con comprensión semántica — ideal para la mayoría de historias. Reconstruye el índice tras grandes cambios.", "settings.advancedAi.ragModeHybrid": "Híbrido (semántico + léxico, recomendado)", "settings.advancedAi.ragModeLabel": "Modo de recuperación de contexto", @@ -121,6 +122,7 @@ "settings.ai.creativity": "Nivel de creatividad de la IA", "settings.ai.creativityDescription": "Los valores más altos producen resultados más inesperados.", "settings.ai.customModel": "Modelo personalizado", + "settings.ai.downloadDesktopCta": "Descargar la aplicación de escritorio", "settings.ai.fallbackNone": "Ninguno", "settings.ai.fallbackStep1": "Primer respaldo", "settings.ai.fallbackStep2": "Segundo respaldo", @@ -204,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "No disponible", "settings.ai.localBackendPreset": "Preajuste de backend local", "settings.ai.ollamaBrowserNote": "Ollama solo está disponible en la aplicación de escritorio. La política de seguridad de contenido del navegador bloquea las conexiones directas a localhost.", - "settings.ai.ollamaHint": "Asegúrate de que ollama serve está en ejecución y CORS está habilitado.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama y los servidores locales compatibles con OpenAI (LM Studio, vLLM) solo están disponibles en la aplicación de escritorio. Los navegadores bloquean las conexiones directas a localhost (Content Security Policy y Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Se requiere la aplicación de escritorio para servidores locales", + "settings.ai.ollamaHint": "Asegúrate de que el servidor esté en ejecución (p. ej. ollama serve). La aplicación de escritorio se conecta directamente, sin configuración CORS.", "settings.ai.ollamaModelHint": "Selección rápida de modelos reportados por tu servidor — toca para usar.", "settings.ai.ollamaServerUrl": "URL del servidor Ollama", "settings.ai.ollamaTauriBypass": "Versión de escritorio: WorldScript llama a Ollama directamente — sin barrera de CORS del navegador.", @@ -236,6 +240,9 @@ "settings.ai.scanLocalPorts": "Escanear puertos locales comunes", "settings.ai.scanNo": "sin respuesta", "settings.ai.scanOk": "accesible", + "settings.ai.scanStateHttp": "error HTTP", + "settings.ai.scanStateTimeout": "tiempo de espera agotado", + "settings.ai.scanUseUrl": "Usar esta URL", "settings.ai.temperature.balanced": "1 – Equilibrado", "settings.ai.temperature.creative": "2 – Creativo", "settings.ai.temperature.precise": "0 – Preciso", @@ -435,24 +442,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Vista previa en vivo", "settings.editor.title": "Preferencias del editor", - "settings.featureFlags.description": "Prueba funciones que aún estamos refinando. Tu opinión define lo que publicamos.", - "settings.featureFlags.category.core": "Escritura", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Flujo de edición", - "settings.featureFlags.category.personalization": "Personalización", "settings.featureFlags.category.analytics": "Analíticas", - "settings.featureFlags.category.performance": "Rendimiento", - "settings.featureFlags.category.voice": "Voz", + "settings.featureFlags.category.core": "Escritura", "settings.featureFlags.category.extensions": "Extensiones", - "settings.featureFlags.category.sync": "Sincronización", "settings.featureFlags.category.i18n": "Idioma y diseño", - "settings.featureFlags.dependency.requires": "Requiere {{name}}", + "settings.featureFlags.category.performance": "Rendimiento", + "settings.featureFlags.category.personalization": "Personalización", + "settings.featureFlags.category.pipeline": "Flujo de edición", + "settings.featureFlags.category.sync": "Sincronización", + "settings.featureFlags.category.voice": "Voz", "settings.featureFlags.dependency.desktopOnly": "Solo en la app de escritorio", - "settings.featureFlags.risk.high": "Puede usar mucha memoria, GPU o presupuesto de tokens.", - "settings.featureFlags.resetToDefaults": "Restablecer valores predeterminados", - "settings.featureFlags.resetTitle": "¿Restablecer las funciones experimentales?", - "settings.featureFlags.resetConfirm": "Esto restaura todas las funciones experimentales a su estado predeterminado (activado/desactivado). Tus proyectos y contenido no se ven afectados.", - "settings.featureFlags.resetDone": "Funciones experimentales restablecidas a los valores predeterminados.", + "settings.featureFlags.dependency.requires": "Requiere {{name}}", + "settings.featureFlags.description": "Prueba funciones que aún estamos refinando. Tu opinión define lo que publicamos.", "settings.featureFlags.enableAdaptiveAiEngine": "Motor IA adaptativo (selección inteligente de backend)", "settings.featureFlags.enableAppHealthPanel": "Instantánea del estado de la app (acerca de)", "settings.featureFlags.enableBinderResearch": "Cuaderno de investigación (barra lateral del manuscrito)", @@ -475,6 +477,11 @@ "settings.featureFlags.enableVoiceSupport": "Comandos de voz y dictado", "settings.featureFlags.enableVoiceWasm": "Motor de voz WASM (Whisper.cpp — sin conexión)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orquestación tipada de trabajadores — Fase 2)", + "settings.featureFlags.resetConfirm": "Esto restaura todas las funciones experimentales a su estado predeterminado (activado/desactivado). Tus proyectos y contenido no se ven afectados.", + "settings.featureFlags.resetDone": "Funciones experimentales restablecidas a los valores predeterminados.", + "settings.featureFlags.resetTitle": "¿Restablecer las funciones experimentales?", + "settings.featureFlags.resetToDefaults": "Restablecer valores predeterminados", + "settings.featureFlags.risk.high": "Puede usar mucha memoria, GPU o presupuesto de tokens.", "settings.featureFlags.title": "Funciones de acceso anticipado", "settings.font.custom": "Fuente personalizada", "settings.font.mono": "Monoespaciado", @@ -604,8 +611,8 @@ "settings.openRouter.modelFetch.loading": "Cargando catálogo de modelos…", "settings.openRouter.modelPlaceholder": "Selecciona o busca un modelo", "settings.openRouter.paidModelNote": "Los modelos de pago requieren créditos en tu cuenta de OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter no está disponible en el modo de IA Local o Eco. Cambia a Híbrido o Nube en IA y Modelos para usarlo.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter está bloqueado porque “Solo almacenamiento local” está activado. Desáctivalo en Privacidad y Datos para permitir la IA en la nube.", + "settings.openRouter.policyBlocked.mode": "OpenRouter no está disponible en el modo de IA Local o Eco. Cambia a Híbrido o Nube en IA y Modelos para usarlo.", "settings.openRouter.preferredModel": "Modelo preferido", "settings.openRouter.resetCircuit": "Restablecer", "settings.openRouter.resetCircuitAria": "Restablecer el cortacircuitos de OpenRouter", @@ -737,8 +744,8 @@ "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", "settings.voice.engine.auto": "Automático (recomendado)", - "settings.voice.engine.wasm": "Modelo WASM local (sin conexión)", "settings.voice.engine.privacyNote": "Privacidad: «Web Speech API» envía audio al proveedor de tu navegador (Google, Apple o Microsoft). «Modelo WASM local» se ejecuta totalmente en tu dispositivo. «Auto» prefiere local y puede recurrir a la nube.", + "settings.voice.engine.wasm": "Modelo WASM local (sin conexión)", "settings.voice.engine.webSpeech": "Web Speech API (nube)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Controla WorldScript Studio con tu voz. Elige abajo un motor de voz en la nube o totalmente local.", @@ -780,6 +787,5 @@ "voice.modelDownload.error": "Descarga fallida: {{error}}", "voice.modelDownload.progress": "{{percent}}% completado", "voice.modelDownload.retry": "Reintentar", - "voice.modelDownload.title": "Descarga de modelo de voz", - "settings.about.productName": "WorldScript Studio" + "voice.modelDownload.title": "Descarga de modelo de voz" } diff --git a/locales/eu/settings.json b/locales/eu/settings.json index 9e47501b..e43c5a51 100644 --- a/locales/eu/settings.json +++ b/locales/eu/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AI Sormen Maila", "settings.ai.creativityDescription": "Balio altuagoek ustekabeko emaitza gehiago sortzen dituzte.", "settings.ai.customModel": "Eredu pertsonalizatua", + "settings.ai.downloadDesktopCta": "Deskargatu mahaigaineko aplikazioa", "settings.ai.fallbackNone": "Bat ere ez", "settings.ai.fallbackStep1": "Lehenengo atzerakada", "settings.ai.fallbackStep2": "Bigarren atzerakada", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ez dago eskuragarri", "settings.ai.localBackendPreset": "Backend lokala aurrez ezarri", "settings.ai.ollamaBrowserNote": "Ollama mahaigaineko aplikazioan bakarrik dago eskuragarri. Arakatzailearen Edukiaren Segurtasun-Politikak lokaleko ostalari konexio zuzenak blokeatzen ditu.", - "settings.ai.ollamaHint": "Ziurtatu ollama zerbitzaria martxan dagoela eta CORS gaituta dagoela.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama eta OpenAI-rekin bateragarriak diren tokiko zerbitzariak (LM Studio, vLLM) mahaigaineko aplikazioan bakarrik daude eskuragarri. Nabigatzaileek localhost-era zuzeneko konexioak blokeatzen dituzte (Edukiaren Segurtasun Politika eta Sare Pribaturako Sarbidea).", + "settings.ai.ollamaDesktopOnlyTitle": "Mahaigaineko aplikazioa behar da tokiko zerbitzarietarako", + "settings.ai.ollamaHint": "Ziurtatu zerbitzaria martxan dagoela (adib. ollama serve). Mahaigaineko aplikazioa zuzenean konektatzen da — ez da CORS konfiguraziorik behar.", "settings.ai.ollamaModelHint": "Aukeratu azkar zure zerbitzariak jakinarazitako ereduak — sakatu erabiltzeko.", "settings.ai.ollamaServerUrl": "Ollama zerbitzariaren URLa", "settings.ai.ollamaTauriBypass": "Mahaigaineko eraikuntza: WorldScript-ek zuzenean deitzen dio Ollamari — ez dago arakatzailearen CORS oztoporik.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Eskaneatu tokiko ataka arruntak", "settings.ai.scanNo": "erantzunik ez", "settings.ai.scanOk": "irisgarria", + "settings.ai.scanStateHttp": "HTTP errorea", + "settings.ai.scanStateTimeout": "denbora-muga gaindituta", + "settings.ai.scanUseUrl": "Erabili URL hau", "settings.ai.temperature.balanced": "1 – Orekatua", "settings.ai.temperature.creative": "2 – Sormena", "settings.ai.temperature.precise": "0 – Zehatza", diff --git a/locales/fa/settings.json b/locales/fa/settings.json index dbd890cf..20f592cf 100644 --- a/locales/fa/settings.json +++ b/locales/fa/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "سطح خلاقیت هوش مصنوعی", "settings.ai.creativityDescription": "مقادیر بالاتر نتایج غیرمنتظره تری ایجاد می کند.", "settings.ai.customModel": "مدل سفارشی", + "settings.ai.downloadDesktopCta": "دانلود برنامه دسکتاپ", "settings.ai.fallbackNone": "هیچ کدام", "settings.ai.fallbackStep1": "اولین بازگشت", "settings.ai.fallbackStep2": "بازگشت دوم", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "در دسترس نیست", "settings.ai.localBackendPreset": "از پیش تنظیم شده باطن محلی", "settings.ai.ollamaBrowserNote": "Ollama فقط در برنامه دسکتاپ در دسترس است. خط مشی امنیت محتوای مرورگر اتصال مستقیم به لوکال هاست را مسدود می کند.", - "settings.ai.ollamaHint": "مطمئن شوید که سرویس olama در حال اجرا است و CORS فعال است.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama و سرورهای محلی سازگار با OpenAI (LM Studio، vLLM) فقط در برنامه دسکتاپ در دسترس هستند. مرورگرها اتصالات مستقیم به localhost را مسدود می‌کنند (سیاست امنیت محتوا و دسترسی به شبکه خصوصی).", + "settings.ai.ollamaDesktopOnlyTitle": "برنامه دسکتاپ برای سرورهای محلی لازم است", + "settings.ai.ollamaHint": "مطمئن شوید سرور در حال اجراست (مثلاً ollama serve). برنامه دسکتاپ مستقیم متصل می‌شود — نیازی به تنظیم CORS نیست.", "settings.ai.ollamaModelHint": "مدل‌های گزارش‌شده توسط سرورتان را سریع انتخاب کنید — برای استفاده ضربه بزنید.", "settings.ai.ollamaServerUrl": "آدرس سرور اوللاما", "settings.ai.ollamaTauriBypass": "ساخت دسکتاپ: WorldScript مستقیماً اوللاما را فرا می‌خواند - بدون مانع CORS مرورگر.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "پورت های محلی رایج را اسکن کنید", "settings.ai.scanNo": "بدون پاسخ", "settings.ai.scanOk": "قابل دسترس", + "settings.ai.scanStateHttp": "خطای HTTP", + "settings.ai.scanStateTimeout": "پایان مهلت", + "settings.ai.scanUseUrl": "استفاده از این نشانی", "settings.ai.temperature.balanced": "1- متعادل", "settings.ai.temperature.creative": "2- خلاق", "settings.ai.temperature.precise": "0 - دقیق", diff --git a/locales/fi/settings.json b/locales/fi/settings.json index 3e12cf3d..9ae4c48f 100644 --- a/locales/fi/settings.json +++ b/locales/fi/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "Tekoälyn luovuustaso", "settings.ai.creativityDescription": "Suuremmat arvot tuottavat enemmän odottamattomia tuloksia.", "settings.ai.customModel": "Mukautettu malli", + "settings.ai.downloadDesktopCta": "Lataa työpöytäsovellus", "settings.ai.fallbackNone": "Ei mitään", "settings.ai.fallbackStep1": "Ensimmäinen takaisku", "settings.ai.fallbackStep2": "Toinen takaisku", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ei saatavilla", "settings.ai.localBackendPreset": "Paikallinen taustajärjestelmän esiasetus", "settings.ai.ollamaBrowserNote": "Ollama on saatavilla vain työpöytäsovelluksessa. Selaimen sisällön suojauskäytäntö estää suorat yhteydet localhostiin.", - "settings.ai.ollamaHint": "Varmista, että ollama-palvelu on käynnissä ja CORS on käytössä.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama ja paikalliset OpenAI-yhteensopivat palvelimet (LM Studio, vLLM) ovat käytettävissä vain työpöytäsovelluksessa. Selaimet estävät suorat yhteydet localhostiin (Content Security Policy ja Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Paikalliset palvelimet vaativat työpöytäsovelluksen", + "settings.ai.ollamaHint": "Varmista, että palvelin on käynnissä (esim. ollama serve). Työpöytäsovellus yhdistää suoraan — CORS-asetuksia ei tarvita.", "settings.ai.ollamaModelHint": "Palvelimesi ilmoittamat pikavalintamallit – käytä napauttamalla.", "settings.ai.ollamaServerUrl": "Ollama-palvelimen URL-osoite", "settings.ai.ollamaTauriBypass": "Työpöytärakenne: WorldScript kutsuu Ollamaa suoraan – ei selaimen CORS-estettä.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Tarkista yleiset paikalliset portit", "settings.ai.scanNo": "ei vastausta", "settings.ai.scanOk": "tavoitettavissa", + "settings.ai.scanStateHttp": "HTTP-virhe", + "settings.ai.scanStateTimeout": "aikakatkaisu", + "settings.ai.scanUseUrl": "Käytä tätä URL-osoitetta", "settings.ai.temperature.balanced": "1 – Tasapainoinen", "settings.ai.temperature.creative": "2 – Luova", "settings.ai.temperature.precise": "0 – Tarkka", diff --git a/locales/fr/settings.json b/locales/fr/settings.json index 2d8c0218..a3c7945d 100644 --- a/locales/fr/settings.json +++ b/locales/fr/settings.json @@ -13,6 +13,7 @@ "settings.about.githubDescription": "Voir le code source, signaler des bugs et contribuer.", "settings.about.githubLabel": "Open-source sur GitHub", "settings.about.liveDemo": "Essayer la démo en ligne", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Version du runtime bureau", "settings.about.title": "À propos de WorldScript Studio", "settings.about.versionLabel": "Version", @@ -63,16 +64,16 @@ "settings.advancedAi.model": "Modèle d'IA", "settings.advancedAi.modelDescription": "Le modèle IA utilisé pour la génération de scènes, l'analyse et d'autres fonctionnalités IA. La disponibilité dépend du fournisseur sélectionné.", "settings.advancedAi.modelRecommendationsIntro": "Points de contrôle locaux populaires (vérifiez les noms dans votre environnement d'exécution) :", - "settings.advancedAi.ollamaPull.recommendedFor": "Recommandé pour votre appareil :", + "settings.advancedAi.ollamaPull.batteryNote": "Taille réduite pour économiser la batterie.", + "settings.advancedAi.ollamaPull.installed": "Installé", "settings.advancedAi.ollamaPull.pull": "Télécharger le modèle", "settings.advancedAi.ollamaPull.pulling": "Téléchargement du modèle…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recommandé pour votre appareil :", "settings.advancedAi.ollamaPull.retry": "Réessayer", - "settings.advancedAi.ollamaPull.installed": "Installé", - "settings.advancedAi.ollamaPull.useModel": "Utiliser ce modèle", - "settings.advancedAi.ollamaPull.batteryNote": "Taille réduite pour économiser la batterie.", "settings.advancedAi.ollamaPull.tier.high-end": "Haut de gamme", - "settings.advancedAi.ollamaPull.tier.mid-range": "Milieu de gamme", "settings.advancedAi.ollamaPull.tier.low-end": "Entrée de gamme", + "settings.advancedAi.ollamaPull.tier.mid-range": "Milieu de gamme", + "settings.advancedAi.ollamaPull.useModel": "Utiliser ce modèle", "settings.advancedAi.ragModeHint": "Le mode hybride associe recherche par mots-clés et compréhension sémantique — idéal pour la plupart des histoires. Reconstruisez l'index après de grandes modifications.", "settings.advancedAi.ragModeHybrid": "Hybride (sémantique + lexical, recommandé)", "settings.advancedAi.ragModeLabel": "Mode de récupération du contexte", @@ -121,6 +122,7 @@ "settings.ai.creativity": "Niveau de créativité de l'IA", "settings.ai.creativityDescription": "Des valeurs plus élevées produisent des résultats plus inattendus.", "settings.ai.customModel": "Modèle personnalisé", + "settings.ai.downloadDesktopCta": "Télécharger l'application de bureau", "settings.ai.fallbackNone": "Aucun", "settings.ai.fallbackStep1": "Premier repli", "settings.ai.fallbackStep2": "Deuxième repli", @@ -204,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Indisponible", "settings.ai.localBackendPreset": "Préréglage backend local", "settings.ai.ollamaBrowserNote": "Ollama n'est disponible que dans l'application de bureau. La politique de sécurité du contenu du navigateur bloque les connexions directes à localhost.", - "settings.ai.ollamaHint": "Assurez-vous qu'ollama serve est en cours d'exécution et que CORS est activé.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama et les serveurs locaux compatibles OpenAI (LM Studio, vLLM) ne sont disponibles que dans l'application de bureau. Les navigateurs bloquent les connexions directes vers localhost (Content Security Policy et Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Application de bureau requise pour les serveurs locaux", + "settings.ai.ollamaHint": "Assurez-vous que le serveur est en cours d'exécution (p. ex. ollama serve). L'application de bureau se connecte directement — aucune configuration CORS nécessaire.", "settings.ai.ollamaModelHint": "Sélection rapide des modèles rapportés par votre serveur — appuyez pour utiliser.", "settings.ai.ollamaServerUrl": "URL du serveur Ollama", "settings.ai.ollamaTauriBypass": "Version bureau : WorldScript appelle Ollama directement — aucune barrière CORS du navigateur.", @@ -236,6 +240,9 @@ "settings.ai.scanLocalPorts": "Scanner les ports locaux courants", "settings.ai.scanNo": "pas de réponse", "settings.ai.scanOk": "accessible", + "settings.ai.scanStateHttp": "erreur HTTP", + "settings.ai.scanStateTimeout": "délai dépassé", + "settings.ai.scanUseUrl": "Utiliser cette URL", "settings.ai.temperature.balanced": "1 – Équilibré", "settings.ai.temperature.creative": "2 – Créatif", "settings.ai.temperature.precise": "0 – Précis", @@ -435,24 +442,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Aperçu en direct", "settings.editor.title": "Préférences de l'éditeur", - "settings.featureFlags.description": "Essayez des fonctionnalités que nous affinons encore. Vos retours façonnent ce qui sera publié.", - "settings.featureFlags.category.core": "Écriture", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Chaîne d'édition", - "settings.featureFlags.category.personalization": "Personnalisation", "settings.featureFlags.category.analytics": "Analyses", - "settings.featureFlags.category.performance": "Performances", - "settings.featureFlags.category.voice": "Voix", + "settings.featureFlags.category.core": "Écriture", "settings.featureFlags.category.extensions": "Extensions", - "settings.featureFlags.category.sync": "Synchronisation", "settings.featureFlags.category.i18n": "Langue et mise en page", - "settings.featureFlags.dependency.requires": "Nécessite {{name}}", + "settings.featureFlags.category.performance": "Performances", + "settings.featureFlags.category.personalization": "Personnalisation", + "settings.featureFlags.category.pipeline": "Chaîne d'édition", + "settings.featureFlags.category.sync": "Synchronisation", + "settings.featureFlags.category.voice": "Voix", "settings.featureFlags.dependency.desktopOnly": "Application de bureau uniquement", - "settings.featureFlags.risk.high": "Peut utiliser beaucoup de mémoire, de GPU ou de budget de jetons.", - "settings.featureFlags.resetToDefaults": "Réinitialiser par défaut", - "settings.featureFlags.resetTitle": "Réinitialiser les fonctionnalités expérimentales ?", - "settings.featureFlags.resetConfirm": "Cela rétablit toutes les fonctionnalités expérimentales à leur état par défaut (activé/désactivé). Vos projets et votre contenu ne sont pas affectés.", - "settings.featureFlags.resetDone": "Fonctionnalités expérimentales réinitialisées par défaut.", + "settings.featureFlags.dependency.requires": "Nécessite {{name}}", + "settings.featureFlags.description": "Essayez des fonctionnalités que nous affinons encore. Vos retours façonnent ce qui sera publié.", "settings.featureFlags.enableAdaptiveAiEngine": "Moteur IA adaptatif (sélection intelligente du backend)", "settings.featureFlags.enableAppHealthPanel": "Instantané de l'état de l'application (à propos)", "settings.featureFlags.enableBinderResearch": "Classeur de recherche (barre latérale du manuscrit)", @@ -475,6 +477,11 @@ "settings.featureFlags.enableVoiceSupport": "Commandes vocales & dictée", "settings.featureFlags.enableVoiceWasm": "Moteur vocal WASM (Whisper.cpp — hors ligne)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orchestration typée de workers — Phase 2)", + "settings.featureFlags.resetConfirm": "Cela rétablit toutes les fonctionnalités expérimentales à leur état par défaut (activé/désactivé). Vos projets et votre contenu ne sont pas affectés.", + "settings.featureFlags.resetDone": "Fonctionnalités expérimentales réinitialisées par défaut.", + "settings.featureFlags.resetTitle": "Réinitialiser les fonctionnalités expérimentales ?", + "settings.featureFlags.resetToDefaults": "Réinitialiser par défaut", + "settings.featureFlags.risk.high": "Peut utiliser beaucoup de mémoire, de GPU ou de budget de jetons.", "settings.featureFlags.title": "Fonctionnalités en accès anticipé", "settings.font.custom": "Police personnalisée", "settings.font.mono": "Monospace", @@ -604,8 +611,8 @@ "settings.openRouter.modelFetch.loading": "Chargement du catalogue de modèles…", "settings.openRouter.modelPlaceholder": "Sélectionner ou rechercher un modèle", "settings.openRouter.paidModelNote": "Les modèles payants nécessitent des crédits sur votre compte OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter est indisponible en mode IA Local ou Éco. Passez en mode Hybride ou Cloud dans IA et Modèles pour l’utiliser.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter est bloqué car « Stockage local uniquement » est activé. Désactivez-le dans Confidentialité et Données pour autoriser l’IA cloud.", + "settings.openRouter.policyBlocked.mode": "OpenRouter est indisponible en mode IA Local ou Éco. Passez en mode Hybride ou Cloud dans IA et Modèles pour l’utiliser.", "settings.openRouter.preferredModel": "Modèle préféré", "settings.openRouter.resetCircuit": "Réinitialiser", "settings.openRouter.resetCircuitAria": "Réinitialiser le disjoncteur OpenRouter", @@ -737,8 +744,8 @@ "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", "settings.voice.engine.auto": "Automatique (recommandé)", - "settings.voice.engine.wasm": "Modèle WASM local (hors ligne)", "settings.voice.engine.privacyNote": "Confidentialité : « Web Speech API » envoie l'audio à l'éditeur de votre navigateur (Google, Apple ou Microsoft). « Modèle WASM local » s'exécute entièrement sur votre appareil. « Auto » privilégie le local et peut basculer vers le cloud.", + "settings.voice.engine.wasm": "Modèle WASM local (hors ligne)", "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Contrôlez WorldScript Studio à la voix. Choisissez ci-dessous un moteur vocal cloud ou entièrement local.", @@ -780,6 +787,5 @@ "voice.modelDownload.error": "Échec du téléchargement : {{error}}", "voice.modelDownload.progress": "{{percent}}% terminé", "voice.modelDownload.retry": "Réessayer", - "voice.modelDownload.title": "Téléchargement du modèle vocal", - "settings.about.productName": "WorldScript Studio" + "voice.modelDownload.title": "Téléchargement du modèle vocal" } diff --git a/locales/he/settings.json b/locales/he/settings.json index cf007d58..a74f3445 100644 --- a/locales/he/settings.json +++ b/locales/he/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "רמת יצירתיות AI", "settings.ai.creativityDescription": "ערכים גבוהים מפיקים תוצאות בלתי צפויות יותר.", "settings.ai.customModel": "מודל מותאם", + "settings.ai.downloadDesktopCta": "הורדת יישום שולחן העבודה", "settings.ai.fallbackNone": "ללא", "settings.ai.fallbackStep1": "חלופה ראשונה", "settings.ai.fallbackStep2": "חלופה שנייה", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "הגדרה מוגדרת מראש של מנוע אחורי מקומי", "settings.ai.ollamaBrowserNote": "‏Ollama זמין רק באפליקציית שולחן העבודה. מדיניות אבטחת התוכן של הדפדפן חוסמת חיבורים ישירים ל‑localhost.", - "settings.ai.ollamaHint": "ודאו ש‑ollama serve פועל ו‑CORS מופעל.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama ושרתים מקומיים תואמי-OpenAI (LM Studio, vLLM) זמינים רק ביישום שולחן העבודה. דפדפנים חוסמים חיבורים ישירים אל localhost (Content Security Policy ו-Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "נדרש יישום שולחני עבור שרתים מקומיים", + "settings.ai.ollamaHint": "ודא שהשרת פועל (למשל ollama serve). יישום שולחן העבודה מתחבר ישירות — אין צורך בהגדרת CORS.", "settings.ai.ollamaModelHint": "מודלי בחירה מהירה שדווחו על ידי השרת שלכם — הקישו לשימוש.", "settings.ai.ollamaServerUrl": "כתובת שרת Ollama", "settings.ai.ollamaTauriBypass": "בניית שולחן עבודה: WorldScript קורא ל‑Ollama ישירות — ללא מחסום CORS של הדפדפן.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "סריקת פורטים מקומיים נפוצים", "settings.ai.scanNo": "אין תגובה", "settings.ai.scanOk": "נגיש", + "settings.ai.scanStateHttp": "שגיאת HTTP", + "settings.ai.scanStateTimeout": "פג תוקף", + "settings.ai.scanUseUrl": "השתמש בכתובת זו", "settings.ai.temperature.balanced": "1 – מאוזן", "settings.ai.temperature.creative": "2 – יצירתי", "settings.ai.temperature.precise": "0 – מדויק", diff --git a/locales/hu/settings.json b/locales/hu/settings.json index e2ebb56a..704e8c12 100644 --- a/locales/hu/settings.json +++ b/locales/hu/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AI kreativitás szintje", "settings.ai.creativityDescription": "A magasabb értékek váratlanabb eredményeket eredményeznek.", "settings.ai.customModel": "Egyedi modell", + "settings.ai.downloadDesktopCta": "Asztali alkalmazás letöltése", "settings.ai.fallbackNone": "Egyik sem", "settings.ai.fallbackStep1": "Első visszaesés", "settings.ai.fallbackStep2": "Második visszaesés", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Nem elérhető", "settings.ai.localBackendPreset": "Helyi háttér előre beállított", "settings.ai.ollamaBrowserNote": "Az Ollama csak az asztali alkalmazásban érhető el. A böngésző tartalombiztonsági házirendje blokkolja a közvetlen kapcsolatot a localhosttal.", - "settings.ai.ollamaHint": "Győződjön meg arról, hogy az ollama szolgáltatás fut, és a CORS engedélyezve van.", + "settings.ai.ollamaDesktopOnlyBody": "Az Ollama és a helyi OpenAI-kompatibilis kiszolgálók (LM Studio, vLLM) csak az asztali alkalmazásban érhetők el. A böngészők blokkolják a localhost felé irányuló közvetlen kapcsolatokat (Content Security Policy és Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Helyi kiszolgálókhoz asztali alkalmazás szükséges", + "settings.ai.ollamaHint": "Győződj meg róla, hogy a kiszolgáló fut (pl. ollama serve). Az asztali alkalmazás közvetlenül kapcsolódik — CORS-beállítás nem szükséges.", "settings.ai.ollamaModelHint": "A kiszolgáló által jelentett modellek gyors kiválasztása – koppintson a használathoz.", "settings.ai.ollamaServerUrl": "Ollama szerver URL-je", "settings.ai.ollamaTauriBypass": "Asztali felépítés: A WorldScript közvetlenül hívja az Ollamát – a böngésző CORS akadálya nélkül.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "A gyakori helyi portok vizsgálata", "settings.ai.scanNo": "nincs válasz", "settings.ai.scanOk": "elérhető", + "settings.ai.scanStateHttp": "HTTP-hiba", + "settings.ai.scanStateTimeout": "időtúllépés", + "settings.ai.scanUseUrl": "URL használata", "settings.ai.temperature.balanced": "1 – Kiegyensúlyozott", "settings.ai.temperature.creative": "2 – Kreatív", "settings.ai.temperature.precise": "0 – Pontos", diff --git a/locales/is/settings.json b/locales/is/settings.json index f324cd4a..16a0244d 100644 --- a/locales/is/settings.json +++ b/locales/is/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AI sköpunarstig", "settings.ai.creativityDescription": "Hærri gildi gefa óvæntari niðurstöður.", "settings.ai.customModel": "Sérsniðin líkan", + "settings.ai.downloadDesktopCta": "Sækja skjáborðsforritið", "settings.ai.fallbackNone": "Engin", "settings.ai.fallbackStep1": "Fyrsta afturför", "settings.ai.fallbackStep2": "Önnur afturför", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ekki í boði", "settings.ai.localBackendPreset": "Forstilla staðbundin bakenda", "settings.ai.ollamaBrowserNote": "Ollama er aðeins fáanlegt í skjáborðsforritinu. Innihaldsöryggisstefna vafrans lokar á beinar tengingar við localhost.", - "settings.ai.ollamaHint": "Gakktu úr skugga um að ollama þjóna sé í gangi og CORS sé virkt.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama og staðværir OpenAI-samhæfðir þjónar (LM Studio, vLLM) eru aðeins í boði í skjáborðsforritinu. Vafrar loka beinum tengingum við localhost (Content Security Policy og Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Skjáborðsforrits er krafist fyrir staðværa þjóna", + "settings.ai.ollamaHint": "Gakktu úr skugga um að þjónninn sé í gangi (t.d. ollama serve). Skjáborðsforritið tengist beint — engin CORS-uppsetning nauðsynleg.", "settings.ai.ollamaModelHint": "Flýtivalsgerðir sem miðlarinn þinn hefur tilkynnt um – bankaðu til að nota.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Skrifborðsbygging: WorldScript hringir beint í Ollama - engin CORS hindrun vafra.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Skannaðu algengar staðbundnar hafnir", "settings.ai.scanNo": "ekkert svar", "settings.ai.scanOk": "náðist", + "settings.ai.scanStateHttp": "HTTP-villa", + "settings.ai.scanStateTimeout": "tímamörk liðin", + "settings.ai.scanUseUrl": "Nota þessa slóð", "settings.ai.temperature.balanced": "1 - Jafnvægi", "settings.ai.temperature.creative": "2 - Skapandi", "settings.ai.temperature.precise": "0 - Nákvæmt", diff --git a/locales/it/settings.json b/locales/it/settings.json index e9ae3c5d..988a56a6 100644 --- a/locales/it/settings.json +++ b/locales/it/settings.json @@ -13,6 +13,7 @@ "settings.about.githubDescription": "Visualizza il codice sorgente, segnala problemi e contribuisci.", "settings.about.githubLabel": "Open-source su GitHub", "settings.about.liveDemo": "Prova la demo dal vivo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Versione runtime desktop", "settings.about.title": "Informazioni su WorldScript Studio", "settings.about.versionLabel": "Versione", @@ -63,16 +64,16 @@ "settings.advancedAi.model": "Modello IA", "settings.advancedAi.modelDescription": "Il modello IA usato per la generazione di scene, analisi e altre funzionalità IA. La disponibilità dipende dal provider selezionato.", "settings.advancedAi.modelRecommendationsIntro": "Checkpoint locali popolari (verifica i nomi nel tuo ambiente di esecuzione):", - "settings.advancedAi.ollamaPull.recommendedFor": "Consigliato per il tuo dispositivo:", + "settings.advancedAi.ollamaPull.batteryNote": "Ridotta la dimensione per risparmiare batteria.", + "settings.advancedAi.ollamaPull.installed": "Installato", "settings.advancedAi.ollamaPull.pull": "Scarica modello", "settings.advancedAi.ollamaPull.pulling": "Download del modello…", + "settings.advancedAi.ollamaPull.recommendedFor": "Consigliato per il tuo dispositivo:", "settings.advancedAi.ollamaPull.retry": "Riprova", - "settings.advancedAi.ollamaPull.installed": "Installato", - "settings.advancedAi.ollamaPull.useModel": "Usa questo modello", - "settings.advancedAi.ollamaPull.batteryNote": "Ridotta la dimensione per risparmiare batteria.", "settings.advancedAi.ollamaPull.tier.high-end": "Fascia alta", - "settings.advancedAi.ollamaPull.tier.mid-range": "Fascia media", "settings.advancedAi.ollamaPull.tier.low-end": "Fascia bassa", + "settings.advancedAi.ollamaPull.tier.mid-range": "Fascia media", + "settings.advancedAi.ollamaPull.useModel": "Usa questo modello", "settings.advancedAi.ragModeHint": "La modalità ibrida combina ricerca per parole chiave e comprensione semantica — ideale per la maggior parte delle storie. Ricostruisci l'indice dopo modifiche importanti.", "settings.advancedAi.ragModeHybrid": "Ibrido (semantico + lessicale, consigliato)", "settings.advancedAi.ragModeLabel": "Modalità di recupero del contesto", @@ -121,6 +122,7 @@ "settings.ai.creativity": "Livello di creatività dell'IA", "settings.ai.creativityDescription": "Valori più alti producono risultati più inaspettati.", "settings.ai.customModel": "Modello personalizzato", + "settings.ai.downloadDesktopCta": "Scarica l'app desktop", "settings.ai.fallbackNone": "Nessuno", "settings.ai.fallbackStep1": "Primo fallback", "settings.ai.fallbackStep2": "Secondo fallback", @@ -204,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Non disponibile", "settings.ai.localBackendPreset": "Preset backend locale", "settings.ai.ollamaBrowserNote": "Ollama è disponibile solo nell'app desktop. La politica di sicurezza dei contenuti del browser blocca le connessioni dirette a localhost.", - "settings.ai.ollamaHint": "Assicurati che ollama serve sia in esecuzione e che CORS sia abilitato.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama e i server locali compatibili con OpenAI (LM Studio, vLLM) sono disponibili solo nell'app desktop. I browser bloccano le connessioni dirette a localhost (Content Security Policy e Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "App desktop richiesta per i server locali", + "settings.ai.ollamaHint": "Assicurati che il server sia in esecuzione (es. ollama serve). L'app desktop si connette direttamente — nessuna configurazione CORS necessaria.", "settings.ai.ollamaModelHint": "Selezione rapida dei modelli segnalati dal tuo server — tocca per usare.", "settings.ai.ollamaServerUrl": "URL del server Ollama", "settings.ai.ollamaTauriBypass": "Versione desktop: WorldScript chiama Ollama direttamente — nessuna barriera CORS del browser.", @@ -236,6 +240,9 @@ "settings.ai.scanLocalPorts": "Scansiona porte locali comuni", "settings.ai.scanNo": "nessuna risposta", "settings.ai.scanOk": "raggiungibile", + "settings.ai.scanStateHttp": "errore HTTP", + "settings.ai.scanStateTimeout": "timeout", + "settings.ai.scanUseUrl": "Usa questo URL", "settings.ai.temperature.balanced": "1 – Equilibrato", "settings.ai.temperature.creative": "2 – Creativo", "settings.ai.temperature.precise": "0 – Preciso", @@ -435,24 +442,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Anteprima in tempo reale", "settings.editor.title": "Preferenze dell'editor", - "settings.featureFlags.description": "Prova funzionalità che stiamo ancora perfezionando. Il tuo feedback determina ciò che verrà pubblicato.", - "settings.featureFlags.category.core": "Scrittura", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Flusso di modifica", - "settings.featureFlags.category.personalization": "Personalizzazione", "settings.featureFlags.category.analytics": "Analisi", - "settings.featureFlags.category.performance": "Prestazioni", - "settings.featureFlags.category.voice": "Voce", + "settings.featureFlags.category.core": "Scrittura", "settings.featureFlags.category.extensions": "Estensioni", - "settings.featureFlags.category.sync": "Sincronizzazione", "settings.featureFlags.category.i18n": "Lingua e layout", - "settings.featureFlags.dependency.requires": "Richiede {{name}}", + "settings.featureFlags.category.performance": "Prestazioni", + "settings.featureFlags.category.personalization": "Personalizzazione", + "settings.featureFlags.category.pipeline": "Flusso di modifica", + "settings.featureFlags.category.sync": "Sincronizzazione", + "settings.featureFlags.category.voice": "Voce", "settings.featureFlags.dependency.desktopOnly": "Solo app desktop", - "settings.featureFlags.risk.high": "Può usare molta memoria, GPU o budget di token.", - "settings.featureFlags.resetToDefaults": "Ripristina valori predefiniti", - "settings.featureFlags.resetTitle": "Ripristinare le funzionalità sperimentali?", - "settings.featureFlags.resetConfirm": "Questo ripristina tutte le funzionalità sperimentali al loro stato predefinito (attivo/disattivo). I tuoi progetti e contenuti non sono interessati.", - "settings.featureFlags.resetDone": "Funzionalità sperimentali ripristinate ai valori predefiniti.", + "settings.featureFlags.dependency.requires": "Richiede {{name}}", + "settings.featureFlags.description": "Prova funzionalità che stiamo ancora perfezionando. Il tuo feedback determina ciò che verrà pubblicato.", "settings.featureFlags.enableAdaptiveAiEngine": "Motore IA adattivo (selezione intelligente del backend)", "settings.featureFlags.enableAppHealthPanel": "Istantanea dello stato dell'app (informazioni)", "settings.featureFlags.enableBinderResearch": "Raccoglitore di ricerca (barra laterale del manoscritto)", @@ -475,6 +477,11 @@ "settings.featureFlags.enableVoiceSupport": "Comandi vocali e dettatura", "settings.featureFlags.enableVoiceWasm": "Motore vocale WASM (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orchestrazione tipizzata dei worker — Fase 2)", + "settings.featureFlags.resetConfirm": "Questo ripristina tutte le funzionalità sperimentali al loro stato predefinito (attivo/disattivo). I tuoi progetti e contenuti non sono interessati.", + "settings.featureFlags.resetDone": "Funzionalità sperimentali ripristinate ai valori predefiniti.", + "settings.featureFlags.resetTitle": "Ripristinare le funzionalità sperimentali?", + "settings.featureFlags.resetToDefaults": "Ripristina valori predefiniti", + "settings.featureFlags.risk.high": "Può usare molta memoria, GPU o budget di token.", "settings.featureFlags.title": "Funzionalità in accesso anticipato", "settings.font.custom": "Carattere personalizzato", "settings.font.mono": "Monospazio", @@ -604,8 +611,8 @@ "settings.openRouter.modelFetch.loading": "Caricamento del catalogo modelli…", "settings.openRouter.modelPlaceholder": "Seleziona o cerca un modello", "settings.openRouter.paidModelNote": "I modelli a pagamento richiedono crediti sul tuo account OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter non è disponibile in modalità IA Locale o Eco. Passa a Ibrida o Cloud in IA e Modelli per usarlo.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter è bloccato perché “Solo archiviazione locale” è attivo. Disattivalo in Privacy e Dati per consentire l’IA nel cloud.", + "settings.openRouter.policyBlocked.mode": "OpenRouter non è disponibile in modalità IA Locale o Eco. Passa a Ibrida o Cloud in IA e Modelli per usarlo.", "settings.openRouter.preferredModel": "Modello preferito", "settings.openRouter.resetCircuit": "Reimposta", "settings.openRouter.resetCircuitAria": "Reimposta l'interruttore di OpenRouter", @@ -737,8 +744,8 @@ "settings.voice.enableHint": "Attiva comandi vocali, dettatura e feedback audio.", "settings.voice.enableLabel": "Abilita controllo vocale", "settings.voice.engine.auto": "Automatico (consigliato)", - "settings.voice.engine.wasm": "Modello WASM locale (offline)", "settings.voice.engine.privacyNote": "Privacy: «Web Speech API» invia l'audio al fornitore del browser (Google, Apple o Microsoft). «Modello WASM locale» funziona interamente sul dispositivo. «Auto» preferisce il locale e può ricorrere al cloud.", + "settings.voice.engine.wasm": "Modello WASM locale (offline)", "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Livello di feedback audio", "settings.voice.intro": "Controlla WorldScript Studio con la voce. Scegli sotto un motore vocale cloud o completamente locale.", @@ -780,6 +787,5 @@ "voice.modelDownload.error": "Download fallito: {{error}}", "voice.modelDownload.progress": "{{percent}}% completato", "voice.modelDownload.retry": "Riprova", - "voice.modelDownload.title": "Download modello vocale", - "settings.about.productName": "WorldScript Studio" + "voice.modelDownload.title": "Download modello vocale" } diff --git a/locales/ja/settings.json b/locales/ja/settings.json index 4d8f6dc6..07107359 100644 --- a/locales/ja/settings.json +++ b/locales/ja/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AIの創造性レベル", "settings.ai.creativityDescription": "値を大きくすると、より予期しない結果が生じます。", "settings.ai.customModel": "カスタムモデル", + "settings.ai.downloadDesktopCta": "デスクトップアプリをダウンロード", "settings.ai.fallbackNone": "なし", "settings.ai.fallbackStep1": "最初のフォールバック", "settings.ai.fallbackStep2": "2 番目のフォールバック", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "利用不可", "settings.ai.localBackendPreset": "ローカル バックエンド プリセット", "settings.ai.ollamaBrowserNote": "Ollama はデスクトップ アプリでのみ利用できます。ブラウザのコンテンツ セキュリティ ポリシーは、ローカルホストへの直接接続をブロックします。", - "settings.ai.ollamaHint": "ollamserve が実行中であり、CORS が有効になっていることを確認してください。", + "settings.ai.ollamaDesktopOnlyBody": "Ollama およびローカルの OpenAI 互換サーバー(LM Studio、vLLM)はデスクトップアプリでのみ利用できます。ブラウザーは localhost への直接接続をブロックします(Content Security Policy および Private Network Access)。", + "settings.ai.ollamaDesktopOnlyTitle": "ローカルサーバーにはデスクトップアプリが必要です", + "settings.ai.ollamaHint": "サーバーが起動していることを確認してください(例: ollama serve)。デスクトップアプリは直接接続するため、CORS の設定は不要です。", "settings.ai.ollamaModelHint": "サーバーから報告されたモデルをクイック選択します — タップして使用します。", "settings.ai.ollamaServerUrl": "オラマサーバーのURL", "settings.ai.ollamaTauriBypass": "デスクトップ ビルド: WorldScript は Ollama を直接呼び出します。ブラウザーの CORS バリアはありません。", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "共通のローカルポートをスキャンする", "settings.ai.scanNo": "応答なし", "settings.ai.scanOk": "到達可能な", + "settings.ai.scanStateHttp": "HTTP エラー", + "settings.ai.scanStateTimeout": "タイムアウト", + "settings.ai.scanUseUrl": "この URL を使用", "settings.ai.temperature.balanced": "1 – バランスのとれた", "settings.ai.temperature.creative": "2 – クリエイティブ", "settings.ai.temperature.precise": "0 – 正確", diff --git a/locales/ko/settings.json b/locales/ko/settings.json index 33c2be24..da9c1d8d 100644 --- a/locales/ko/settings.json +++ b/locales/ko/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AI 창의성 수준", "settings.ai.creativityDescription": "값이 높을수록 예상치 못한 결과가 더 많이 발생합니다.", "settings.ai.customModel": "맞춤형 모델", + "settings.ai.downloadDesktopCta": "데스크톱 앱 다운로드", "settings.ai.fallbackNone": "없음", "settings.ai.fallbackStep1": "첫 번째 대체", "settings.ai.fallbackStep2": "두 번째 대체", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "사용할 수 없음", "settings.ai.localBackendPreset": "로컬 백엔드 사전 설정", "settings.ai.ollamaBrowserNote": "Ollama는 데스크톱 앱에서만 사용할 수 있습니다. 브라우저의 콘텐츠 보안 정책은 localhost에 대한 직접 연결을 차단합니다.", - "settings.ai.ollamaHint": "ollama 서비스가 실행 중이고 CORS가 활성화되어 있는지 확인하세요.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama 및 로컬 OpenAI 호환 서버(LM Studio, vLLM)는 데스크톱 앱에서만 사용할 수 있습니다. 브라우저는 localhost에 대한 직접 연결을 차단합니다(Content Security Policy 및 Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "로컬 서버에는 데스크톱 앱이 필요합니다", + "settings.ai.ollamaHint": "서버가 실행 중인지 확인하세요(예: ollama serve). 데스크톱 앱은 직접 연결하므로 CORS 설정이 필요하지 않습니다.", "settings.ai.ollamaModelHint": "서버에서 보고한 모델을 빠르게 선택하세요. 탭하여 사용하세요.", "settings.ai.ollamaServerUrl": "올라마 서버 URL", "settings.ai.ollamaTauriBypass": "데스크탑 빌드: WorldScript는 브라우저 CORS 장벽 없이 Ollama를 직접 호출합니다.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "공통 로컬 포트 ​​스캔", "settings.ai.scanNo": "응답 없음", "settings.ai.scanOk": "도달 가능", + "settings.ai.scanStateHttp": "HTTP 오류", + "settings.ai.scanStateTimeout": "시간 초과", + "settings.ai.scanUseUrl": "이 URL 사용", "settings.ai.temperature.balanced": "1 - 균형 잡힌", "settings.ai.temperature.creative": "2 – 창의적", "settings.ai.temperature.precise": "0 – 정확함", diff --git a/locales/pt/settings.json b/locales/pt/settings.json index bddaf423..c81df80f 100644 --- a/locales/pt/settings.json +++ b/locales/pt/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "IA Creativity Level", "settings.ai.creativityDescription": "Valores mais altos produzem resultados mais inesperados.", "settings.ai.customModel": "Modelo personalizado", + "settings.ai.downloadDesktopCta": "Transferir a aplicação de desktop", "settings.ai.fallbackNone": "Nenhum", "settings.ai.fallbackStep1": "Primeiro substituto", "settings.ai.fallbackStep2": "Segundo substituto", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Indisponível", "settings.ai.localBackendPreset": "Predefinição de back-end local", "settings.ai.ollamaBrowserNote": "Ollama está disponível apenas no aplicativo de desktop. A Política de Segurança de Conteúdo do navegador bloqueia conexões diretas com o host local.", - "settings.ai.ollamaHint": "Certifique-se de que ollama serve esteja em execução e que o CORS esteja ativado.", + "settings.ai.ollamaDesktopOnlyBody": "O Ollama e os servidores locais compatíveis com OpenAI (LM Studio, vLLM) só estão disponíveis na aplicação de desktop. Os navegadores bloqueiam ligações diretas a localhost (Content Security Policy e Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Aplicação de desktop necessária para servidores locais", + "settings.ai.ollamaHint": "Certifique-se de que o servidor está em execução (p. ex. ollama serve). A aplicação de desktop liga-se diretamente — sem configuração CORS.", "settings.ai.ollamaModelHint": "Selecione rapidamente os modelos relatados pelo seu servidor – toque para usar.", "settings.ai.ollamaServerUrl": "URL do servidor Ollama", "settings.ai.ollamaTauriBypass": "Construção para desktop: WorldScript chama Ollama diretamente – sem barreira CORS do navegador.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Digitalize portas locais comuns", "settings.ai.scanNo": "sem resposta", "settings.ai.scanOk": "alcançável", + "settings.ai.scanStateHttp": "erro HTTP", + "settings.ai.scanStateTimeout": "tempo limite excedido", + "settings.ai.scanUseUrl": "Usar este URL", "settings.ai.temperature.balanced": "1 – Equilibrado", "settings.ai.temperature.creative": "2 – Criativo", "settings.ai.temperature.precise": "0 – Preciso", diff --git a/locales/ru/settings.json b/locales/ru/settings.json index 42f49c41..b6653bde 100644 --- a/locales/ru/settings.json +++ b/locales/ru/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "Уровень творчества ИИ", "settings.ai.creativityDescription": "Более высокие значения дают более неожиданные результаты.", "settings.ai.customModel": "Пользовательская модель", + "settings.ai.downloadDesktopCta": "Скачать настольное приложение", "settings.ai.fallbackNone": "Никто", "settings.ai.fallbackStep1": "Первый запасной вариант", "settings.ai.fallbackStep2": "Второй запасной вариант", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Нет в наличии", "settings.ai.localBackendPreset": "Локальная настройка серверной части", "settings.ai.ollamaBrowserNote": "Оллама доступен только в настольном приложении. Политика безопасности контента браузера блокирует прямые подключения к локальному хосту.", - "settings.ai.ollamaHint": "Убедитесь, что служба ollama работает и CORS включен.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama и локальные OpenAI-совместимые серверы (LM Studio, vLLM) доступны только в настольном приложении. Браузеры блокируют прямые подключения к localhost (Content Security Policy и Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Для локальных серверов требуется настольное приложение", + "settings.ai.ollamaHint": "Убедитесь, что сервер запущен (например, ollama serve). Настольное приложение подключается напрямую — настройка CORS не требуется.", "settings.ai.ollamaModelHint": "Быстрый выбор моделей, о которых сообщает ваш сервер. Нажмите, чтобы использовать.", "settings.ai.ollamaServerUrl": "URL-адрес сервера Оллама", "settings.ai.ollamaTauriBypass": "Сборка для настольных компьютеров: WorldScript напрямую вызывает Ollama — без барьера CORS браузера.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Сканировать общие локальные порты", "settings.ai.scanNo": "нет ответа", "settings.ai.scanOk": "достижимый", + "settings.ai.scanStateHttp": "ошибка HTTP", + "settings.ai.scanStateTimeout": "тайм-аут", + "settings.ai.scanUseUrl": "Использовать этот URL", "settings.ai.temperature.balanced": "1 – Сбалансированный", "settings.ai.temperature.creative": "2 – Креатив", "settings.ai.temperature.precise": "0 – Точный", diff --git a/locales/sv/settings.json b/locales/sv/settings.json index 940f4b96..5d95a098 100644 --- a/locales/sv/settings.json +++ b/locales/sv/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "AI-kreativitetsnivå", "settings.ai.creativityDescription": "Högre värden ger mer oväntade resultat.", "settings.ai.customModel": "Anpassad modell", + "settings.ai.downloadDesktopCta": "Ladda ner skrivbordsappen", "settings.ai.fallbackNone": "Ingen", "settings.ai.fallbackStep1": "Första fallback", "settings.ai.fallbackStep2": "Andra fallback", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ej tillgängligt", "settings.ai.localBackendPreset": "Lokal förinställning av backend", "settings.ai.ollamaBrowserNote": "Ollama är endast tillgänglig i skrivbordsappen. Webbläsarens innehållssäkerhetspolicy blockerar direktanslutningar till localhost.", - "settings.ai.ollamaHint": "Se till att ollamaserven körs och att CORS är aktiverat.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama och lokala OpenAI-kompatibla servrar (LM Studio, vLLM) är endast tillgängliga i skrivbordsappen. Webbläsare blockerar direkta anslutningar till localhost (Content Security Policy och Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Skrivbordsappen krävs för lokala servrar", + "settings.ai.ollamaHint": "Se till att servern körs (t.ex. ollama serve). Skrivbordsappen ansluter direkt — ingen CORS-konfiguration behövs.", "settings.ai.ollamaModelHint": "Snabbvalsmodeller rapporterade av din server – tryck för att använda.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Skrivbordsbygge: WorldScript anropar Ollama direkt — ingen CORS-barriär för webbläsaren.", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "Skanna vanliga lokala portar", "settings.ai.scanNo": "inget svar", "settings.ai.scanOk": "nås", + "settings.ai.scanStateHttp": "HTTP-fel", + "settings.ai.scanStateTimeout": "tidsgräns överskriden", + "settings.ai.scanUseUrl": "Använd den här URL:en", "settings.ai.temperature.balanced": "1 – Balanserad", "settings.ai.temperature.creative": "2 – Kreativt", "settings.ai.temperature.precise": "0 – Exakt", diff --git a/locales/zh/settings.json b/locales/zh/settings.json index 8b00e071..371c6c40 100644 --- a/locales/zh/settings.json +++ b/locales/zh/settings.json @@ -122,6 +122,7 @@ "settings.ai.creativity": "人工智能创造力水平", "settings.ai.creativityDescription": "较高的值会产生更多意想不到的结果。", "settings.ai.customModel": "定制型号", + "settings.ai.downloadDesktopCta": "下载桌面应用", "settings.ai.fallbackNone": "没有任何", "settings.ai.fallbackStep1": "第一个后备", "settings.ai.fallbackStep2": "第二次后备", @@ -205,7 +206,9 @@ "settings.ai.localAi.webgpuUnavailable": "不可用", "settings.ai.localBackendPreset": "本地后端预设", "settings.ai.ollamaBrowserNote": "Ollama 仅在桌面应用程序中可用。浏览器的内容安全策略阻止与本地主机的直接连接。", - "settings.ai.ollamaHint": "确保 ollama 服务正在运行并且 CORS 已启用。", + "settings.ai.ollamaDesktopOnlyBody": "Ollama 和本地 OpenAI 兼容服务器(LM Studio、vLLM)仅在桌面应用中可用。浏览器会阻止与 localhost 的直接连接(内容安全策略和专用网络访问)。", + "settings.ai.ollamaDesktopOnlyTitle": "本地服务器需要桌面应用", + "settings.ai.ollamaHint": "请确保服务器正在运行(例如 ollama serve)。桌面应用直接连接,无需配置 CORS。", "settings.ai.ollamaModelHint": "快速选择服务器报告的模型 - 点击即可使用。", "settings.ai.ollamaServerUrl": "奥拉马服务器 URL", "settings.ai.ollamaTauriBypass": "桌面构建:WorldScript 直接调用 Ollama — 无浏览器 CORS 障碍。", @@ -237,6 +240,9 @@ "settings.ai.scanLocalPorts": "扫描本地常用端口", "settings.ai.scanNo": "没有回应", "settings.ai.scanOk": "可达的", + "settings.ai.scanStateHttp": "HTTP 错误", + "settings.ai.scanStateTimeout": "超时", + "settings.ai.scanUseUrl": "使用此 URL", "settings.ai.temperature.balanced": "1 – 平衡", "settings.ai.temperature.creative": "2 – 创意", "settings.ai.temperature.precise": "0 – 精确", diff --git a/public/locales/ar/bundle.json b/public/locales/ar/bundle.json index 3c53bb28..5d153c5b 100644 --- a/public/locales/ar/bundle.json +++ b/public/locales/ar/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "مستوى إبداع الذكاء الاصطناعي", "settings.ai.creativityDescription": "القيم الأعلى تنتج نتائج أكثر غير متوقّعة.", "settings.ai.customModel": "نموذج مخصّص", + "settings.ai.downloadDesktopCta": "تنزيل تطبيق سطح المكتب", "settings.ai.fallbackNone": "لا شيء", "settings.ai.fallbackStep1": "الاحتياطي الأول", "settings.ai.fallbackStep2": "الاحتياطي الثاني", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "إعداد مسبق للخلفية المحلية", "settings.ai.ollamaBrowserNote": "‏Ollama متاح فقط في تطبيق سطح المكتب. تمنع سياسة أمان المحتوى للمتصفّح الاتصالات المباشرة بـ localhost.", - "settings.ai.ollamaHint": "تأكّد من تشغيل ollama serve وتفعيل CORS.", + "settings.ai.ollamaDesktopOnlyBody": "يتوفر Ollama والخوادم المحلية المتوافقة مع OpenAI (LM Studio وvLLM) فقط في تطبيق سطح المكتب. تحظر المتصفحات الاتصالات المباشرة بـ localhost (سياسة أمان المحتوى والوصول إلى الشبكة الخاصة).", + "settings.ai.ollamaDesktopOnlyTitle": "تطبيق سطح المكتب مطلوب للخوادم المحلية", + "settings.ai.ollamaHint": "تأكد من تشغيل الخادم (مثل ollama serve). يتصل تطبيق سطح المكتب مباشرة — دون الحاجة إلى إعداد CORS.", "settings.ai.ollamaModelHint": "نماذج اختيار سريع مُبلَّغ عنها من خادمك — انقر للاستخدام.", "settings.ai.ollamaServerUrl": "عنوان خادم Ollama", "settings.ai.ollamaTauriBypass": "بناء سطح المكتب: يستدعي WorldScript ‏Ollama مباشرة — بلا حاجز CORS للمتصفّح.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "مسح المنافذ المحلية الشائعة", "settings.ai.scanNo": "لا استجابة", "settings.ai.scanOk": "يمكن الوصول إليه", + "settings.ai.scanStateHttp": "خطأ HTTP", + "settings.ai.scanStateTimeout": "انتهت المهلة", + "settings.ai.scanUseUrl": "استخدام هذا الرابط", "settings.ai.temperature.balanced": "1 – متوازن", "settings.ai.temperature.creative": "2 – إبداعي", "settings.ai.temperature.precise": "0 – دقيق", diff --git a/public/locales/de/bundle.json b/public/locales/de/bundle.json index 2b7f44b8..e7df01cf 100644 --- a/public/locales/de/bundle.json +++ b/public/locales/de/bundle.json @@ -1621,6 +1621,7 @@ "settings.about.githubDescription": "Quellcode ansehen, Fehler melden und mitmachen.", "settings.about.githubLabel": "Open-Source auf GitHub", "settings.about.liveDemo": "Live-Demo ausprobieren", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Desktop-Laufzeitversion", "settings.about.title": "Über WorldScript Studio", "settings.about.versionLabel": "Version", @@ -1671,16 +1672,16 @@ "settings.advancedAi.model": "KI-Modell", "settings.advancedAi.modelDescription": "Das KI-Modell für Szenengeneration, Analyse und andere KI-Funktionen. Die Verfügbarkeit hängt vom gewählten Anbieter ab.", "settings.advancedAi.modelRecommendationsIntro": "Beliebte lokale Checkpoints (Namen im Runtime überprüfen):", - "settings.advancedAi.ollamaPull.recommendedFor": "Für dein Gerät empfohlen:", + "settings.advancedAi.ollamaPull.batteryNote": "Eine Größe kleiner gewählt, um Akku zu sparen.", + "settings.advancedAi.ollamaPull.installed": "Installiert", "settings.advancedAi.ollamaPull.pull": "Modell laden", "settings.advancedAi.ollamaPull.pulling": "Modell wird geladen…", + "settings.advancedAi.ollamaPull.recommendedFor": "Für dein Gerät empfohlen:", "settings.advancedAi.ollamaPull.retry": "Erneut versuchen", - "settings.advancedAi.ollamaPull.installed": "Installiert", - "settings.advancedAi.ollamaPull.useModel": "Dieses Modell verwenden", - "settings.advancedAi.ollamaPull.batteryNote": "Eine Größe kleiner gewählt, um Akku zu sparen.", "settings.advancedAi.ollamaPull.tier.high-end": "High-End", - "settings.advancedAi.ollamaPull.tier.mid-range": "Mittelklasse", "settings.advancedAi.ollamaPull.tier.low-end": "Einsteiger", + "settings.advancedAi.ollamaPull.tier.mid-range": "Mittelklasse", + "settings.advancedAi.ollamaPull.useModel": "Dieses Modell verwenden", "settings.advancedAi.ragModeHint": "Der Hybrid-Modus verbindet Keyword-Suche mit semantischem Verständnis — ideal für die meisten Geschichten. Index nach großen Änderungen neu aufbauen.", "settings.advancedAi.ragModeHybrid": "Hybrid (semantisch + lexikalisch, empfohlen)", "settings.advancedAi.ragModeLabel": "Kontext-Abrufmodus", @@ -1729,6 +1730,7 @@ "settings.ai.creativity": "KI-Kreativitätsstufe", "settings.ai.creativityDescription": "Höhere Werte erzeugen unerwartetere Ergebnisse.", "settings.ai.customModel": "Benutzerdefiniertes Modell", + "settings.ai.downloadDesktopCta": "Desktop-App herunterladen", "settings.ai.fallbackNone": "Keiner", "settings.ai.fallbackStep1": "Erster Fallback", "settings.ai.fallbackStep2": "Zweiter Fallback", @@ -1812,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Nicht verfügbar", "settings.ai.localBackendPreset": "Lokales Backend-Preset", "settings.ai.ollamaBrowserNote": "Ollama ist nur in der Desktop-App verfügbar. Die Browser-CSP blockiert direkte Verbindungen zu localhost.", - "settings.ai.ollamaHint": "Stellen Sie sicher, dass ollama serve läuft und CORS aktiviert ist.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama und lokale OpenAI-kompatible Server (LM Studio, vLLM) sind nur in der Desktop-App verfügbar. Browser blockieren direkte Verbindungen zu localhost (Content Security Policy und Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Desktop-App für lokale Server erforderlich", + "settings.ai.ollamaHint": "Stelle sicher, dass der Server läuft (z. B. ollama serve). Die Desktop-App verbindet sich direkt — kein CORS-Setup nötig.", "settings.ai.ollamaModelHint": "Modelle vom Server schnell auswählen — antippen zum Verwenden.", "settings.ai.ollamaServerUrl": "Ollama-Server-URL", "settings.ai.ollamaTauriBypass": "Desktop-Build: WorldScript spricht Ollama direkt an — keine Browser-CORS-Hürde.", @@ -1844,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Gängige lokale Ports scannen", "settings.ai.scanNo": "keine Antwort", "settings.ai.scanOk": "erreichbar", + "settings.ai.scanStateHttp": "HTTP-Fehler", + "settings.ai.scanStateTimeout": "Zeitüberschreitung", + "settings.ai.scanUseUrl": "Diese URL übernehmen", "settings.ai.temperature.balanced": "1 – Ausgewogen", "settings.ai.temperature.creative": "2 – Kreativ", "settings.ai.temperature.precise": "0 – Präzise", @@ -2043,24 +2050,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Live-Vorschau", "settings.editor.title": "Editor-Einstellungen", - "settings.featureFlags.description": "Probiere Funktionen aus, an denen wir noch arbeiten. Dein Feedback formt, was als Nächstes erscheint.", - "settings.featureFlags.category.core": "Schreiben", "settings.featureFlags.category.ai": "KI", - "settings.featureFlags.category.pipeline": "Bearbeitungs-Pipeline", - "settings.featureFlags.category.personalization": "Personalisierung", "settings.featureFlags.category.analytics": "Analyse", - "settings.featureFlags.category.performance": "Leistung", - "settings.featureFlags.category.voice": "Sprachsteuerung", + "settings.featureFlags.category.core": "Schreiben", "settings.featureFlags.category.extensions": "Erweiterungen", - "settings.featureFlags.category.sync": "Synchronisierung", "settings.featureFlags.category.i18n": "Sprache & Layout", - "settings.featureFlags.dependency.requires": "Erfordert {{name}}", + "settings.featureFlags.category.performance": "Leistung", + "settings.featureFlags.category.personalization": "Personalisierung", + "settings.featureFlags.category.pipeline": "Bearbeitungs-Pipeline", + "settings.featureFlags.category.sync": "Synchronisierung", + "settings.featureFlags.category.voice": "Sprachsteuerung", "settings.featureFlags.dependency.desktopOnly": "Nur Desktop-App", - "settings.featureFlags.risk.high": "Kann erheblichen Arbeitsspeicher, GPU oder Token-Budget beanspruchen.", - "settings.featureFlags.resetToDefaults": "Auf Standard zurücksetzen", - "settings.featureFlags.resetTitle": "Experimentelle Funktionen zurücksetzen?", - "settings.featureFlags.resetConfirm": "Dadurch werden alle experimentellen Funktionen auf ihren Standardzustand (ein/aus) zurückgesetzt. Deine Projekte und Inhalte sind nicht betroffen.", - "settings.featureFlags.resetDone": "Experimentelle Funktionen auf Standard zurückgesetzt.", + "settings.featureFlags.dependency.requires": "Erfordert {{name}}", + "settings.featureFlags.description": "Probiere Funktionen aus, an denen wir noch arbeiten. Dein Feedback formt, was als Nächstes erscheint.", "settings.featureFlags.enableAdaptiveAiEngine": "Adaptiver KI-Motor (hardware-adaptive Backend-Auswahl)", "settings.featureFlags.enableAppHealthPanel": "App-Gesundheit (Über „Info“)", "settings.featureFlags.enableBinderResearch": "Recherche-Binder (Manuskript-Seitenleiste)", @@ -2083,6 +2085,11 @@ "settings.featureFlags.enableVoiceSupport": "Sprachbefehle & Diktat", "settings.featureFlags.enableVoiceWasm": "Sprach-WASM-Engine (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (typisierter Worker-Orchestrator — Phase 2)", + "settings.featureFlags.resetConfirm": "Dadurch werden alle experimentellen Funktionen auf ihren Standardzustand (ein/aus) zurückgesetzt. Deine Projekte und Inhalte sind nicht betroffen.", + "settings.featureFlags.resetDone": "Experimentelle Funktionen auf Standard zurückgesetzt.", + "settings.featureFlags.resetTitle": "Experimentelle Funktionen zurücksetzen?", + "settings.featureFlags.resetToDefaults": "Auf Standard zurücksetzen", + "settings.featureFlags.risk.high": "Kann erheblichen Arbeitsspeicher, GPU oder Token-Budget beanspruchen.", "settings.featureFlags.title": "Early-Access-Funktionen", "settings.font.custom": "Benutzerdefinierte Schriftart", "settings.font.mono": "Monospace", @@ -2212,8 +2219,8 @@ "settings.openRouter.modelFetch.loading": "Modellkatalog wird geladen …", "settings.openRouter.modelPlaceholder": "Modell auswählen oder suchen", "settings.openRouter.paidModelNote": "Kostenpflichtige Modelle benötigen Guthaben auf deinem OpenRouter-Konto.", - "settings.openRouter.policyBlocked.mode": "OpenRouter ist im KI-Modus „Lokal“ oder „Eco“ nicht verfügbar. Wechsle unter „KI & Modelle“ zu Hybrid oder Cloud, um es zu nutzen.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter ist blockiert, weil „Nur lokaler Speicher“ aktiviert ist. Deaktiviere es unter „Datenschutz & Daten“, um Cloud-KI zu erlauben.", + "settings.openRouter.policyBlocked.mode": "OpenRouter ist im KI-Modus „Lokal“ oder „Eco“ nicht verfügbar. Wechsle unter „KI & Modelle“ zu Hybrid oder Cloud, um es zu nutzen.", "settings.openRouter.preferredModel": "Bevorzugtes Modell", "settings.openRouter.resetCircuit": "Zurücksetzen", "settings.openRouter.resetCircuitAria": "OpenRouter-Schutzschalter zurücksetzen", @@ -2345,8 +2352,8 @@ "settings.voice.enableHint": "Aktiviert Sprachbefehle, Diktat und akustisches Feedback.", "settings.voice.enableLabel": "Sprachunterstützung aktivieren", "settings.voice.engine.auto": "Automatisch (empfohlen)", - "settings.voice.engine.wasm": "Lokales WASM-Modell (offline)", "settings.voice.engine.privacyNote": "Datenschutz: „Web Speech API“ sendet Audio an deinen Browser-Anbieter (Google, Apple oder Microsoft). „Lokales WASM-Modell“ läuft vollständig auf deinem Gerät. „Auto“ bevorzugt lokal und greift ggf. auf die Cloud zurück.", + "settings.voice.engine.wasm": "Lokales WASM-Modell (offline)", "settings.voice.engine.webSpeech": "Web Speech API (Cloud)", "settings.voice.feedbackLevel": "Audio-Feedback-Stufe", "settings.voice.intro": "Steuere WorldScript Studio mit deiner Stimme. Wähle unten eine Cloud- oder vollständig lokale Sprach-Engine.", @@ -2389,7 +2396,6 @@ "voice.modelDownload.progress": "{{percent}}% abgeschlossen", "voice.modelDownload.retry": "Wiederholen", "voice.modelDownload.title": "Sprachmodell-Download", - "settings.about.productName": "WorldScript Studio", "sidebar.characterGraph": "Charaktergraph", "sidebar.characterInterviews": "Charakterinterviews", "sidebar.characters": "Charaktere", diff --git a/public/locales/el/bundle.json b/public/locales/el/bundle.json index 46c87a27..e5425c3f 100644 --- a/public/locales/el/bundle.json +++ b/public/locales/el/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "Επίπεδο δημιουργικότητας AI", "settings.ai.creativityDescription": "Οι υψηλότερες τιμές παράγουν περισσότερα απροσδόκητα αποτελέσματα.", "settings.ai.customModel": "Προσαρμοσμένο μοντέλο", + "settings.ai.downloadDesktopCta": "Λήψη της εφαρμογής επιφάνειας εργασίας", "settings.ai.fallbackNone": "Κανένας", "settings.ai.fallbackStep1": "Πρώτη εναλλακτική", "settings.ai.fallbackStep2": "Δεύτερη εναλλακτική", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Μη διαθέσιμο", "settings.ai.localBackendPreset": "Τοπική προεπιλογή υποστήριξης", "settings.ai.ollamaBrowserNote": "Το Olama είναι διαθέσιμο μόνο στην εφαρμογή για υπολογιστές. Η Πολιτική Ασφάλειας Περιεχομένου του προγράμματος περιήγησης αποκλείει τις άμεσες συνδέσεις με τον localhost.", - "settings.ai.ollamaHint": "Βεβαιωθείτε ότι η υπηρεσία ollama εκτελείται και ότι το CORS είναι ενεργοποιημένο.", + "settings.ai.ollamaDesktopOnlyBody": "Το Ollama και οι τοπικοί διακομιστές συμβατοί με OpenAI (LM Studio, vLLM) είναι διαθέσιμοι μόνο στην εφαρμογή επιφάνειας εργασίας. Τα προγράμματα περιήγησης αποκλείουν απευθείας συνδέσεις με το localhost (Content Security Policy και Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Απαιτείται εφαρμογή επιφάνειας εργασίας για τοπικούς διακομιστές", + "settings.ai.ollamaHint": "Βεβαιωθείτε ότι ο διακομιστής εκτελείται (π.χ. ollama serve). Η εφαρμογή επιφάνειας εργασίας συνδέεται απευθείας — δεν απαιτείται ρύθμιση CORS.", "settings.ai.ollamaModelHint": "Γρήγορη επιλογή μοντέλων που αναφέρονται από τον διακομιστή σας — πατήστε για χρήση.", "settings.ai.ollamaServerUrl": "Διεύθυνση URL διακομιστή Olama", "settings.ai.ollamaTauriBypass": "Κατασκευή επιφάνειας εργασίας: Το WorldScript καλεί απευθείας τον Ollama — χωρίς φραγμό CORS του προγράμματος περιήγησης.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Σάρωση κοινών τοπικών θυρών", "settings.ai.scanNo": "καμία απάντηση", "settings.ai.scanOk": "προσιτό", + "settings.ai.scanStateHttp": "σφάλμα HTTP", + "settings.ai.scanStateTimeout": "λήξη χρονικού ορίου", + "settings.ai.scanUseUrl": "Χρήση αυτού του URL", "settings.ai.temperature.balanced": "1 – Ισορροπημένο", "settings.ai.temperature.creative": "2 – Δημιουργικό", "settings.ai.temperature.precise": "0 – Ακριβές", diff --git a/public/locales/en/bundle.json b/public/locales/en/bundle.json index cda093bf..76acef4a 100644 --- a/public/locales/en/bundle.json +++ b/public/locales/en/bundle.json @@ -1170,7 +1170,7 @@ "help.docs.pwaDesktop.title": "PWA & desktop packaging", "help.docs.ragPipeline.content": "

    RAG & Prompt Assembly

    WorldScript's retrieval-augmented generation (RAG) pipeline enriches every AI request with relevant passages from your own manuscript — so the model knows your story before it writes the next line.

    • Building the index: Go to Settings → Advanced AI → Rebuild local search index. WorldScript splits your manuscript into overlapping ~200-token chunks and encodes each with MiniLM-L6-v2 (384-dimensional embeddings) running locally via Transformers.js.
    • Hybrid retrieval: When a request is made, the pipeline scores candidate chunks three ways — semantic cosine similarity (~60%), lexical keyword overlap (~30%), and recency (favoring later chapters, ~10%) — then selects the top-K passages.
    • Prompt assembly: assembleRAGPrompt() builds a token-budgeted context block from the selected chunks and prepends it to the AI prompt. The chunk badge in the Writer panel shows how many passages were injected.
    • Where RAG is used: Continue Writing, Brainstorm, AI Critic, and Plot Board \"Suggest next beat\" all use the same pipeline when RAG is enabled.
    • Rebuild triggers: Rebuild the index after importing a backup, adding many new characters, or when AI completions seem unfamiliar with your story's details.
    • Privacy: The index lives entirely in your browser's OPFS. Manuscript text is never uploaded to build the index — only the final assembled prompt travels to your chosen cloud provider.
    ", "help.docs.ragPipeline.title": "RAG & prompt assembly", - "help.docs.tauriDesktop.content": "

    Tauri Desktop App

    The WorldScript Studio desktop app wraps the same React codebase in a native Tauri v2 shell (Rust). It adds capabilities that browsers cannot provide while keeping your data fully local.

    What the Desktop App Adds

    • Native filesystem access: Read and write files directly via the Tauri fs plugin — no browser file picker required for every operation. Logs are written to $APPDATA/logs/worldscript-YYYY-MM-DD.jsonl.
    • Ollama on localhost: Cloud AI providers block localhost connections in the browser (CSP); the desktop app bypasses this restriction, letting Ollama serve models at localhost:11434 without a proxy.
    • Window-state persistence: Window size, position, and maximized state are restored exactly on each launch via the Tauri window-state plugin.
    • Native menu bar: A File / Edit / View / Help menu bar following OS conventions (macOS: menu in toolbar; Windows/Linux: embedded in the window).
    • Auto-updater: The Tauri updater plugin checks the GitHub releases JSON endpoint on startup and shows a banner under Settings → About when a new version is available. Click Install update to download and apply it in the background.
    • Open data folder: Settings → Data → Open data folder opens the OS file explorer at the directory where IndexedDB and OPFS data are stored — useful for manual backups.
    • Stronghold (optional): The tauri-plugin-stronghold can store the IDB encryption passphrase in the OS keychain so the unlock modal never appears on desktop.

    Installers & Distribution

    The Tauri CI workflow builds platform-specific installers on every tagged release (v*): .dmg for macOS (code-signed), .msi / .exe for Windows (code-signed), .AppImage and .deb for Linux. Installers are attached to GitHub Releases and referenced by the auto-updater endpoint.

    Data Location

    On desktop, data lives in the Tauri app data directory — typically %APPDATA%\\WorldScript Studio on Windows, ~/Library/Application Support/WorldScript Studio on macOS, and ~/.local/share/worldscript-studio on Linux. You can safely copy this directory for a full manual backup.

    ", + "help.docs.tauriDesktop.content": "

    Tauri Desktop App

    The WorldScript Studio desktop app wraps the same React codebase in a native Tauri v2 shell (Rust). It adds capabilities that browsers cannot provide while keeping your data fully local.

    What the Desktop App Adds

    • Native filesystem access: Read and write files directly via the Tauri fs plugin — no browser file picker required for every operation. Logs are written to $APPDATA/logs/worldscript-YYYY-MM-DD.jsonl.
    • Local AI servers (Ollama, LM Studio, vLLM): Browsers block direct localhost connections (CSP + Private Network Access); the desktop app routes these calls through the native Tauri HTTP stack — no proxy and no OLLAMA_ORIGINS setup needed. Use Settings → AI → Scan common local ports to auto-detect servers at localhost:11434 (Ollama), :1234 (LM Studio) and :8000 (vLLM), then adopt a found URL with one click.
    • Window-state persistence: Window size, position, and maximized state are restored exactly on each launch via the Tauri window-state plugin.
    • Native menu bar: A File / Edit / View / Help menu bar following OS conventions (macOS: menu in toolbar; Windows/Linux: embedded in the window).
    • Auto-updater: The Tauri updater plugin checks the GitHub releases JSON endpoint on startup and shows a banner under Settings → About when a new version is available. Click Install update to download and apply it in the background.
    • Open data folder: Settings → Data → Open data folder opens the OS file explorer at the directory where IndexedDB and OPFS data are stored — useful for manual backups.
    • Stronghold (optional): The tauri-plugin-stronghold can store the IDB encryption passphrase in the OS keychain so the unlock modal never appears on desktop.

    Installers & Distribution

    The Tauri CI workflow builds platform-specific installers on every tagged release (v*): .dmg for macOS (code-signed), .msi / .exe for Windows (code-signed), .AppImage and .deb for Linux. Installers are attached to GitHub Releases and referenced by the auto-updater endpoint.

    Data Location

    On desktop, data lives in the Tauri app data directory — typically %APPDATA%\\WorldScript Studio on Windows, ~/Library/Application Support/WorldScript Studio on macOS, and ~/.local/share/worldscript-studio on Linux. You can safely copy this directory for a full manual backup.

    ", "help.docs.tauriDesktop.title": "Tauri desktop app", "help.faq.api.content": "

    Do I Need an API Key?

    Only for cloud AI providers. You can use WorldScript for all writing, the Plot Board, characters, version control, and export without any API key. AI features with local providers also need no key.

    Cloud providers (require an API key)

    • Google Gemini (recommended — free tier available): Get a free key from Google AI Studio. Enter it under Settings → AI Models → Gemini API key. Recommended models: gemini-2.5-flash for everyday use, gemini-2.5-pro for complex tasks.
    • OpenAI: GPT-4o and GPT-4o-mini. Get a key from platform.openai.com. Enter it under Settings → AI Models → OpenAI key. Strong at instruction-following and prose rewriting.
    • Anthropic (Claude): Claude 3.5 Sonnet and Claude 3 Haiku. Get a key from console.anthropic.com. Enter it under Settings → AI Models → Anthropic key. Excellent for long-form narrative and nuanced tone.
    • Grok (xAI): Grok-2. Get a key from the xAI developer portal. Enter it under Settings → AI Models → xAI key. Competitive on creative tasks with lower cost per token than GPT-4.

    Local providers (no API key required)

    • WebLLM (browser, GPU): Runs quantized LLMs (Llama 3.2, Phi-3.5 Mini, Gemma 2) directly in the browser via WebGPU. Download a model under Settings → Advanced AI → Local AI models. Once downloaded, inference runs fully offline at zero cost.
    • ONNX Runtime Web (browser, CPU): WASM-based inference without a GPU. Works on any device; slower than WebLLM but suitable for short completions and classification tasks.
    • Transformers.js: Runs the local RAG embedding model automatically in the background. No configuration needed — it starts when RAG context is enabled.
    • Ollama (desktop app only): Connects to a locally-running Ollama server at localhost:11434. Requires the Tauri desktop app. Run ollama pull llama3.2 to get started. Zero API cost, fully private, supports any Ollama-compatible model including LoRA adapters.

    Key security

    Every API key is encrypted with AES-256-GCM (PBKDF2, 600,000 SHA-256 iterations) before being stored in IndexedDB. The plaintext key is never written to disk, never stored in localStorage, and never sent to any WorldScript server. You can store keys for multiple providers simultaneously and switch between them without re-entering them.

    ", "help.faq.api.title": "Do I need an API key?", @@ -1178,7 +1178,7 @@ "help.faq.offline.title": "Can I work offline?", "help.faq.privacy.content": "

    Your Story Stays On Your Device

    Yes, completely. WorldScript Studio is local-first by design — there is no WorldScript account, no cloud server, and no company that can access your manuscripts. All data lives in your browser's IndexedDB and OPFS, storage that only your device can read.

    What stays local (everything, by default)

    • Manuscripts, characters, and world-building — never transmitted anywhere unless you explicitly send a specific passage to an AI provider for processing.
    • API keys — encrypted at rest with AES-256-GCM (PBKDF2, 600,000 SHA-256 iterations) before being saved to IndexedDB. The plaintext key is never written to disk, never stored in localStorage, and never sent to any WorldScript server.
    • Snapshots and backups — stored entirely in your browser's IndexedDB. Exported JSON files go directly to your device's downloads folder.
    • RAG index and DuckDB analytics — manuscript chunks, vector embeddings, and analytics data all live in your browser's OPFS. Only the final assembled prompt, not the raw index, is ever sent to a provider.

    What leaves your device (only when you choose)

    • Cloud AI requests: When you use Gemini, OpenAI, Anthropic, or Grok, only the text you explicitly submitted for that specific action is sent to the provider. WorldScript adds no hidden telemetry to these requests.
    • AI provider data policies: Each provider has its own data-retention terms. Google Gemini API requests are not used to train Google's models by default. Check your chosen provider's developer terms for the current policy.
    • Collaboration (opt-in only): If you enable P2P collaboration, Yjs document updates are end-to-end encrypted (AES-256-GCM + PBKDF2) before leaving the browser. The signaling server coordinates connections but never sees your manuscript content.

    Go fully offline

    Switch to a local AI provider — WebLLM in the browser or Ollama on the desktop app — or disable AI features entirely. In fully offline mode, zero data is transmitted anywhere. Writing, version control, export, and all settings work without any network connection.

    ", "help.faq.privacy.title": "Is my story private?", - "help.faq.providers.content": "

    Which AI Provider Should I Use?

    WorldScript supports multiple AI providers. Here is a quick guide to help you choose.

    • Google Gemini (cloud): The default. Gemini Flash is fast and free-tier friendly; Gemini Pro gives higher quality. Requires a free API key from Google AI Studio. Best for: everyday writing assistance.
    • OpenAI (cloud): GPT-4o and GPT-4o-mini via API key. Strong instruction-following and prose rewriting. Best for: users already on the OpenAI ecosystem.
    • Ollama (local — desktop only): Runs models on your machine via localhost:11434. Requires the Tauri desktop app. Best for: maximum privacy and zero API cost with any Ollama-supported model.
    • WebLLM (local — browser): GPU inference directly in the browser; no server, no API key. Models are downloaded once and cached. Best for: privacy without the desktop app, fully offline after first download.
    • Hybrid fallback: Enable under Settings → Advanced AI to chain providers automatically — e.g., try Gemini first, fall back to Ollama on error. Useful for resilient workflows.
    ", + "help.faq.providers.content": "

    Which AI Provider Should I Use?

    WorldScript supports multiple AI providers. Here is a quick guide to help you choose.

    • Google Gemini (cloud): The default. Gemini Flash is fast and free-tier friendly; Gemini Pro gives higher quality. Requires a free API key from Google AI Studio. Best for: everyday writing assistance.
    • OpenAI (cloud): GPT-4o and GPT-4o-mini via API key. Strong instruction-following and prose rewriting. Best for: users already on the OpenAI ecosystem.
    • Ollama (local — desktop only): Runs models on your machine via localhost:11434. Requires the Tauri desktop app (browsers block localhost connections); the Scan common local ports button in Settings → AI auto-detects Ollama, LM Studio and vLLM. Best for: maximum privacy and zero API cost with any Ollama-supported model.
    • WebLLM (local — browser): GPU inference directly in the browser; no server, no API key. Models are downloaded once and cached. Best for: privacy without the desktop app, fully offline after first download.
    • Hybrid fallback: Enable under Settings → Advanced AI to chain providers automatically — e.g., try Gemini first, fall back to Ollama on error. Useful for resilient workflows.
    ", "help.faq.providers.title": "Which AI provider should I use?", "help.faq.saving.content": "

    Your entire project, including all text and AI-generated images, is saved automatically and continuously in your web browser's local storage (a database called IndexedDB). This means your work is persisted on your computer between sessions. A 'Saving...' indicator appears in the header when changes are being written, followed by 'All changes saved'.

    There is no cloud account or server-side storage. This ensures complete privacy but also means you are responsible for creating backups using the 'Export Backup' feature in Settings.

    ", "help.faq.saving.title": "How is my project data saved?", @@ -1621,6 +1621,7 @@ "settings.about.githubDescription": "View source code, report issues, and contribute.", "settings.about.githubLabel": "Open-source on GitHub", "settings.about.liveDemo": "Try the live demo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Desktop runtime version", "settings.about.title": "About WorldScript Studio", "settings.about.versionLabel": "Version", @@ -1671,16 +1672,16 @@ "settings.advancedAi.model": "AI Model", "settings.advancedAi.modelDescription": "The AI model used for scene generation, analysis, and other AI-powered features. Model availability depends on your selected provider.", "settings.advancedAi.modelRecommendationsIntro": "Popular local checkpoints (verify names in your runtime):", - "settings.advancedAi.ollamaPull.recommendedFor": "Recommended for your device:", + "settings.advancedAi.ollamaPull.batteryNote": "Stepped down a size to save battery.", + "settings.advancedAi.ollamaPull.installed": "Installed", "settings.advancedAi.ollamaPull.pull": "Pull model", "settings.advancedAi.ollamaPull.pulling": "Downloading model…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recommended for your device:", "settings.advancedAi.ollamaPull.retry": "Retry", - "settings.advancedAi.ollamaPull.installed": "Installed", - "settings.advancedAi.ollamaPull.useModel": "Use this model", - "settings.advancedAi.ollamaPull.batteryNote": "Stepped down a size to save battery.", "settings.advancedAi.ollamaPull.tier.high-end": "High-end", - "settings.advancedAi.ollamaPull.tier.mid-range": "Mid-range", "settings.advancedAi.ollamaPull.tier.low-end": "Low-end", + "settings.advancedAi.ollamaPull.tier.mid-range": "Mid-range", + "settings.advancedAi.ollamaPull.useModel": "Use this model", "settings.advancedAi.ragModeHint": "Hybrid mode blends keyword matching with semantic understanding — best for most stories. Rebuild the index after large edits.", "settings.advancedAi.ragModeHybrid": "Hybrid (semantic + lexical, recommended)", "settings.advancedAi.ragModeLabel": "Context retrieval mode", @@ -1690,85 +1691,6 @@ "settings.advancedAi.temperature": "Temperature", "settings.advancedAi.temperatureDescription": "Controls randomness. Higher values produce more creative, unpredictable text; lower values make output more focused and deterministic.", "settings.advancedAi.title": "Advanced AI Settings", - "settings.aiMode.title": "AI Execution Mode", - "settings.aiMode.description": "Choose how the app processes AI requests. Cloud mode uses your API key for best quality, Local mode runs everything on your device for maximum privacy, and Hybrid mode automatically picks the best option.", - "settings.aiMode.hybrid": "Hybrid (Smart)", - "settings.aiMode.hybridDesc": "Automatically uses local models when preloaded, otherwise falls back to the cloud. Best of both worlds.", - "settings.aiMode.cloud": "Cloud", - "settings.aiMode.cloudDesc": "All AI requests are sent to the cloud provider (Gemini, OpenAI, etc.). Best quality, requires an API key and internet connection.", - "settings.aiMode.local": "Local", - "settings.aiMode.localDesc": "All AI runs on your device using local models. No data leaves the device. Works completely offline once models are preloaded.", - "settings.aiMode.eco": "Eco", - "settings.aiMode.ecoDesc": "Battery-saving mode for low-end or mobile devices. Uses only the small 0.5B text model and rule-based heuristics. No cloud, no heavy models.", - "settings.aiMode.activeLabel": "Active: {{mode}}", - "settings.aiMode.indicator.cloud": "Cloud", - "settings.aiMode.indicator.local": "Local", - "settings.aiMode.indicator.hybrid": "Hybrid", - "settings.aiMode.indicator.eco": "Eco", - "settings.aiMode.indicator.tooltip.cloud": "Cloud mode — all AI calls go to your cloud provider", - "settings.aiMode.indicator.tooltip.local": "Local mode — all AI runs on your device", - "settings.aiMode.indicator.tooltip.hybrid": "Hybrid mode — cloud first, local as offline fallback", - "settings.aiMode.indicator.tooltip.eco": "Eco mode — smallest local model, no cloud, battery-saving", - "settings.aiMode.indicator.orCircuitOpen": "OpenRouter paused (too many rate limits). Falling back to other providers.", - "settings.aiMode.indicatorAriaLabel": "Active AI mode", - "settings.aiMode.indicator.openRouter": "OpenRouter", - "settings.aiMode.indicator.openRouterFree": "OpenRouter Free", - "settings.aiMode.indicator.orShort": "OR ⚠", - "settings.aiMode.indicator.rpm": "{{count}}/20 RPM", - "settings.aiMode.hint.webgpuMissing": "WebGPU not detected — on-device models may run slowly or fall back to a smaller engine.", - "settings.aiMode.hint.cloudOffline": "You're offline — Cloud mode can't reach the AI provider. Reconnect or switch to Local/Eco.", - "settings.aiMode.hint.hybridOffline": "You're offline — Hybrid mode will use the on-device fallback until you reconnect.", - "settings.openRouter.title": "OpenRouter", - "settings.openRouter.description": "Use OpenRouter as a unified cloud gateway. Free-tier models (marked with :free) need no paid credits.", - "settings.openRouter.enabled": "Enable OpenRouter", - "settings.openRouter.enabledHint": "When enabled, OpenRouter is preferred for cloud AI calls unless the active mode forbids cloud.", - "settings.openRouter.apiKey": "API Key", - "settings.openRouter.apiKeyPlaceholder": "sk-or-v1-…", - "settings.openRouter.apiKeyHint": "Stored encrypted on this device.", - "settings.openRouter.apiKeyAriaLabel": "OpenRouter API key", - "settings.openRouter.keyStatus.set": "Key stored — enter a new key to replace it", - "settings.openRouter.keyStatus.unset": "No API key stored", - "settings.openRouter.keyStatus.saving": "Saving…", - "settings.openRouter.keyStatus.saved": "API key saved", - "settings.openRouter.keyStatus.removed": "API key removed", - "settings.openRouter.keyError.empty": "Please enter an OpenRouter API key", - "settings.openRouter.keyError.saveFailed": "Failed to save the API key", - "settings.openRouter.keyError.invalid": "The API key appears invalid", - "settings.openRouter.keyError.network": "Network error while validating the key", - "settings.openRouter.preferredModel": "Preferred Model", - "settings.openRouter.modelPlaceholder": "Select or search a model", - "settings.openRouter.modelAriaLabel": "Preferred OpenRouter model", - "settings.openRouter.customModelLabel": "Custom model…", - "settings.openRouter.customModelPlaceholder": "deepseek/deepseek-r1:free", - "settings.openRouter.customModelAriaLabel": "Custom model identifier", - "settings.openRouter.modelFetch.loading": "Loading model catalog…", - "settings.openRouter.modelFetch.failed": "Could not load model catalog", - "settings.openRouter.modelFetch.empty": "No models found", - "settings.openRouter.freeTierNote": "Free-tier models: 20 req/min, 50 req/day without credits", - "settings.openRouter.freeModel.deepseekR1": "DeepSeek R1 (free)", - "settings.openRouter.freeModel.llama3370b": "Llama 3.3 70B Instruct (free)", - "settings.openRouter.freeModel.qwen2572b": "Qwen 2.5 72B Instruct (free)", - "settings.openRouter.freeModel.gemma327b": "Gemma 3 27B IT (free)", - "settings.openRouter.freeModel.mistral7b": "Mistral 7B Instruct (free)", - "settings.openRouter.paidModelNote": "Paid models require credits on your OpenRouter account.", - "settings.openRouter.policyBlocked.mode": "OpenRouter is unavailable while the AI mode is Local or Eco. Switch to Hybrid or Cloud in AI & Models to use it.", - "settings.openRouter.policyBlocked.localOnly": "OpenRouter is blocked because “Local storage only” is on. Turn it off in Privacy & Data to allow cloud AI.", - "settings.openRouter.getKeyLink": "Get a free API key at openrouter.ai/keys", - "settings.openRouter.testConnection": "Test connection", - "settings.openRouter.testConnectionOk": "Connection successful", - "settings.openRouter.testConnectionFailed": "Connection failed", - "settings.openRouter.saveKey": "Save", - "settings.openRouter.clearKey": "Remove", - "settings.openRouter.circuitBreaker": "Circuit breaker:", - "settings.openRouter.circuitOpen": "Open (paused 5 min)", - "settings.openRouter.circuitClosed": "Closed (healthy)", - "settings.openRouter.resetCircuit": "Reset", - "settings.openRouter.resetCircuitAria": "Reset OpenRouter circuit breaker", - "settings.openRouter.rpmLabel": "Requests / min (last 60 s)", - "settings.openRouter.modeWarning.local": "OpenRouter is disabled while AI mode is set to local-only.", - "settings.openRouter.modeWarning.offline": "OpenRouter is paused because the device is offline.", - "settings.openRouter.errors.generic": "An unexpected OpenRouter error occurred", - "settings.categories.openrouter": "OpenRouter", "settings.advancedAi.topP": "Top P", "settings.advancedAi.topPDescription": "Nucleus sampling threshold. Only tokens whose cumulative probability reaches this value are considered. Lower values = more focused output.", "settings.advancedEditor.autoComplete": "Auto-Complete Suggestions", @@ -1808,6 +1730,7 @@ "settings.ai.creativity": "AI Creativity Level", "settings.ai.creativityDescription": "Higher values produce more unexpected results.", "settings.ai.customModel": "Custom Model", + "settings.ai.downloadDesktopCta": "Download the desktop app", "settings.ai.fallbackNone": "None", "settings.ai.fallbackStep1": "First fallback", "settings.ai.fallbackStep2": "Second fallback", @@ -1836,15 +1759,64 @@ "settings.ai.loadModels": "Load models", "settings.ai.localAi.cancelAriaLabel": "Cancel model download", "settings.ai.localAi.cancelButton": "Cancel", + "settings.ai.localAi.clearBusy": "Local AI is busy right now — try clearing again once it finishes.", + "settings.ai.localAi.clearButton": "Clear Local Models", + "settings.ai.localAi.clearCancel": "Cancel", + "settings.ai.localAi.clearConfirm": "Delete all downloaded local models? They will re-download the next time you use local AI.", + "settings.ai.localAi.clearConfirmYes": "Delete models", + "settings.ai.localAi.clearFailed": "Could not clear local models. Please try again.", + "settings.ai.localAi.clearedAnnounce": "Cleared {{count}} local model cache(s)", + "settings.ai.localAi.clearingButton": "Clearing…", + "settings.ai.localAi.detecting": "Detecting…", + "settings.ai.localAi.deviceClassLabel": "Device class", + "settings.ai.localAi.docsLink": "Local AI setup & troubleshooting", + "settings.ai.localAi.downloadButton": "Download", "settings.ai.localAi.downloadCancelled": "Download cancelled", "settings.ai.localAi.downloadEta": "approx. {{seconds}}s remaining", + "settings.ai.localAi.downloadFailed": "Download failed. Please try again.", "settings.ai.localAi.downloadTitle": "Downloading AI model…", "settings.ai.localAi.downloadedLabel": "downloaded", + "settings.ai.localAi.downloadingButton": "Downloading…", + "settings.ai.localAi.fallbackIntro": "When a layer is unavailable, the Co-Pilot automatically tries the next one:", + "settings.ai.localAi.fallbackLayer1": "WebGPU (WebLLM) — fastest and highest quality; needs a capable GPU.", + "settings.ai.localAi.fallbackLayer2": "WASM (ONNX) — runs on the CPU when no GPU is available.", + "settings.ai.localAi.fallbackLayer3": "Transformers.js — lightweight last-resort generator.", + "settings.ai.localAi.fallbackLayer4": "Heuristic — always-available offline stub when no model can run.", + "settings.ai.localAi.fallbackTitle": "Fallback chain", + "settings.ai.localAi.modelLabel.gemma3_1b": "Gemma 3 1B (~0.8 GB)", + "settings.ai.localAi.modelLabel.gemma3_4b": "Gemma 3 4B (~4.9 GB)", + "settings.ai.localAi.modelLabel.llama32_1b": "Llama 3.2 1B (fast, ~0.7 GB)", + "settings.ai.localAi.modelLabel.llama32_3b": "Llama 3.2 3B (~1.8 GB)", + "settings.ai.localAi.modelLabel.llama33_70b": "Llama 3.3 70B (high-end, ~35 GB)", + "settings.ai.localAi.modelLabel.phi4mini": "Phi-4 Mini 3.8B (~2.3 GB)", + "settings.ai.localAi.modelLabel.qwen25_05b": "Qwen 2.5 0.5B (eco, ~0.4 GB)", + "settings.ai.localAi.modelReadyAnnounce": "{{model}} is ready for offline use", + "settings.ai.localAi.modelsDescription": "Download a model to use it offline. Larger models are higher quality but need more storage and a capable GPU.", + "settings.ai.localAi.modelsTitle": "Models", + "settings.ai.localAi.onboardingHint": "No local model downloaded yet. Download one below to enable offline AI — the first download may take a few minutes.", + "settings.ai.localAi.perfNoData": "Download and run a model to measure throughput.", + "settings.ai.localAi.perfThroughput": "Last local run: {{tps}} tokens/sec", "settings.ai.localAi.progressAriaLabel": "Model download progress", + "settings.ai.localAi.readyBadge": "Ready", + "settings.ai.localAi.recommendedModel": "Recommended for your device: {{model}}", + "settings.ai.localAi.requiresGpuNote": "Without WebGPU, models run on a slower CPU/WASM fallback or download may be unavailable.", "settings.ai.localAi.retryButton": "Retry", + "settings.ai.localAi.sectionDescription": "Run inference on your device. No data leaves the browser. Capability, downloads, and storage are managed here.", + "settings.ai.localAi.sectionTitle": "Local AI", + "settings.ai.localAi.sizeWarning": "Needs ~{{size}} MB; only {{free}} MB free", + "settings.ai.localAi.storageAriaLabel": "Local storage usage", + "settings.ai.localAi.storageModelsCached": "{{count}} local model cache(s) on disk", + "settings.ai.localAi.storageTitle": "Storage", + "settings.ai.localAi.storageUnsupported": "Storage estimates are not available in this browser.", + "settings.ai.localAi.storageUsage": "{{used}} MB of {{quota}} MB used ({{percent}}%)", + "settings.ai.localAi.webgpuAvailable": "Available", + "settings.ai.localAi.webgpuLabel": "WebGPU", + "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "Local backend preset", "settings.ai.ollamaBrowserNote": "Ollama is only available in the desktop app. The browser's Content Security Policy blocks direct connections to localhost.", - "settings.ai.ollamaHint": "Make sure ollama serve is running and CORS is enabled.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama and local OpenAI-compatible servers (LM Studio, vLLM) are only available in the desktop app. Browsers block direct connections to localhost (Content Security Policy and Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Desktop app required for local servers", + "settings.ai.ollamaHint": "Make sure the server is running (e.g. ollama serve). The desktop app connects directly — no CORS setup needed.", "settings.ai.ollamaModelHint": "Quick-select models reported by your server — tap to use.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Desktop build: WorldScript calls Ollama directly — no browser CORS barrier.", @@ -1876,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Scan common local ports", "settings.ai.scanNo": "no response", "settings.ai.scanOk": "reachable", + "settings.ai.scanStateHttp": "HTTP error", + "settings.ai.scanStateTimeout": "timeout", + "settings.ai.scanUseUrl": "Use this URL", "settings.ai.temperature.balanced": "1 – Balanced", "settings.ai.temperature.creative": "2 – Creative", "settings.ai.temperature.precise": "0 – Precise", @@ -1899,6 +1874,34 @@ "settings.ai.webllm.tabLeaderNote": "Only one browser tab runs local inference at a time.", "settings.ai.webllm.vramLabel": "VRAM tier", "settings.ai.webllmHint": "Runs entirely in your browser via WebGPU (optional packages). Large model downloads on first use; use Ollama on desktop for heavier models.", + "settings.aiMode.activeLabel": "Active: {{mode}}", + "settings.aiMode.cloud": "Cloud", + "settings.aiMode.cloudDesc": "All AI requests are sent to the cloud provider (Gemini, OpenAI, etc.). Best quality, requires an API key and internet connection.", + "settings.aiMode.description": "Choose how the app processes AI requests. Cloud mode uses your API key for best quality, Local mode runs everything on your device for maximum privacy, and Hybrid mode automatically picks the best option.", + "settings.aiMode.eco": "Eco", + "settings.aiMode.ecoDesc": "Battery-saving mode for low-end or mobile devices. Uses only the small 0.5B text model and rule-based heuristics. No cloud, no heavy models.", + "settings.aiMode.hint.cloudOffline": "You're offline — Cloud mode can't reach the AI provider. Reconnect or switch to Local/Eco.", + "settings.aiMode.hint.hybridOffline": "You're offline — Hybrid mode will use the on-device fallback until you reconnect.", + "settings.aiMode.hint.webgpuMissing": "WebGPU not detected — on-device models may run slowly or fall back to a smaller engine.", + "settings.aiMode.hybrid": "Hybrid (Smart)", + "settings.aiMode.hybridDesc": "Automatically uses local models when preloaded, otherwise falls back to the cloud. Best of both worlds.", + "settings.aiMode.indicator.cloud": "Cloud", + "settings.aiMode.indicator.eco": "Eco", + "settings.aiMode.indicator.hybrid": "Hybrid", + "settings.aiMode.indicator.local": "Local", + "settings.aiMode.indicator.openRouter": "OpenRouter", + "settings.aiMode.indicator.openRouterFree": "OpenRouter Free", + "settings.aiMode.indicator.orCircuitOpen": "OpenRouter paused (too many rate limits). Falling back to other providers.", + "settings.aiMode.indicator.orShort": "OR ⚠", + "settings.aiMode.indicator.rpm": "{{count}}/20 RPM", + "settings.aiMode.indicator.tooltip.cloud": "Cloud mode — all AI calls go to your cloud provider", + "settings.aiMode.indicator.tooltip.eco": "Eco mode — smallest local model, no cloud, battery-saving", + "settings.aiMode.indicator.tooltip.hybrid": "Hybrid mode — cloud first, local as offline fallback", + "settings.aiMode.indicator.tooltip.local": "Local mode — all AI runs on your device", + "settings.aiMode.indicatorAriaLabel": "Active AI mode", + "settings.aiMode.local": "Local", + "settings.aiMode.localDesc": "All AI runs on your device using local models. No data leaves the device. Works completely offline once models are preloaded.", + "settings.aiMode.title": "AI Execution Mode", "settings.apiKey.configured": "API Key Configured", "settings.apiKey.encryptedNote": "Encrypted and stored in IndexedDB", "settings.apiKey.errorEmpty": "Please enter an API key", @@ -1949,7 +1952,9 @@ "settings.categories.general": "General", "settings.categories.guide": "Settings guide", "settings.categories.integrations": "Integrations", + "settings.categories.localAi": "Local AI", "settings.categories.loraAdapters": "LoRA Adapters", + "settings.categories.openrouter": "OpenRouter", "settings.categories.plugins": "Plugins", "settings.categories.privacy": "Privacy & Security", "settings.categories.privacyData": "Privacy & Data", @@ -2045,24 +2050,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Live Preview", "settings.editor.title": "Editor Preferences", - "settings.featureFlags.description": "Try features we're still refining. Your feedback shapes what ships next.", - "settings.featureFlags.category.core": "Writing", "settings.featureFlags.category.ai": "AI", - "settings.featureFlags.category.pipeline": "Editing Pipeline", - "settings.featureFlags.category.personalization": "Personalization", "settings.featureFlags.category.analytics": "Analytics", - "settings.featureFlags.category.performance": "Performance", - "settings.featureFlags.category.voice": "Voice", + "settings.featureFlags.category.core": "Writing", "settings.featureFlags.category.extensions": "Extensions", - "settings.featureFlags.category.sync": "Sync", "settings.featureFlags.category.i18n": "Language & Layout", - "settings.featureFlags.dependency.requires": "Requires {{name}}", + "settings.featureFlags.category.performance": "Performance", + "settings.featureFlags.category.personalization": "Personalization", + "settings.featureFlags.category.pipeline": "Editing Pipeline", + "settings.featureFlags.category.sync": "Sync", + "settings.featureFlags.category.voice": "Voice", "settings.featureFlags.dependency.desktopOnly": "Desktop app only", - "settings.featureFlags.risk.high": "May use significant memory, GPU, or token budget.", - "settings.featureFlags.resetToDefaults": "Reset to defaults", - "settings.featureFlags.resetTitle": "Reset experimental features?", - "settings.featureFlags.resetConfirm": "This restores every experimental feature to its default on/off state. Your projects and content are not affected.", - "settings.featureFlags.resetDone": "Experimental features reset to defaults.", + "settings.featureFlags.dependency.requires": "Requires {{name}}", + "settings.featureFlags.description": "Try features we're still refining. Your feedback shapes what ships next.", "settings.featureFlags.enableAdaptiveAiEngine": "Adaptive AI engine (hardware-aware backend selection)", "settings.featureFlags.enableAppHealthPanel": "App health snapshot (About)", "settings.featureFlags.enableBinderResearch": "Research binder (Manuscript sidebar)", @@ -2070,6 +2070,7 @@ "settings.featureFlags.enableCompileWizard": "Compile wizard (Export)", "settings.featureFlags.enableComputeShaders": "WebGPU compute shaders (GPU-accelerated RAG & attention)", "settings.featureFlags.enableDuckDbAnalytics": "Advanced analytics (fast story database)", + "settings.featureFlags.enableGlobalCopilot": "Global AI Copilot (beginner-friendly in-app live assistant)", "settings.featureFlags.enableIdbAtRestEncryption": "IDB at-rest encryption (AES-256-GCM) — enable via Settings › Privacy", "settings.featureFlags.enableLocalFirstSync": "Local-First sync (shadow — experimental)", "settings.featureFlags.enableLoraAdapters": "LoRA adapter inference (experimental)", @@ -2079,12 +2080,16 @@ "settings.featureFlags.enableProForge": "ProForge Pipeline (8-stage agentic editing)", "settings.featureFlags.enableProjectHealthScore": "Project health score (Dashboard)", "settings.featureFlags.enableRtlLayout": "RTL layout (experimental)", - "settings.featureFlags.enableGlobalCopilot": "Global AI Copilot (beginner-friendly in-app live assistant)", "settings.featureFlags.enableRustCompute": "Rust Compute (Tauri TaskSupervisor offloading — Phase 2)", "settings.featureFlags.enableStoryBibleAdvanced": "Story Bible advanced (graph + hints in Codex)", "settings.featureFlags.enableVoiceSupport": "Voice commands & dictation", "settings.featureFlags.enableVoiceWasm": "Voice WASM engine (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (typed worker orchestration — Phase 2)", + "settings.featureFlags.resetConfirm": "This restores every experimental feature to its default on/off state. Your projects and content are not affected.", + "settings.featureFlags.resetDone": "Experimental features reset to defaults.", + "settings.featureFlags.resetTitle": "Reset experimental features?", + "settings.featureFlags.resetToDefaults": "Reset to defaults", + "settings.featureFlags.risk.high": "May use significant memory, GPU, or token budget.", "settings.featureFlags.title": "Early Access Features", "settings.font.custom": "Custom Font", "settings.font.mono": "Monospace", @@ -2119,6 +2124,8 @@ "settings.guide.integrations.desc": "LanguageTool and external sync.", "settings.guide.integrations.title": "Integrations", "settings.guide.intro": "Overview of every settings category. Use search at the top of Settings to jump quickly.", + "settings.guide.localAi.desc": "Run the AI on your device — check capability, download models, manage storage, and review the offline fallback chain.", + "settings.guide.localAi.title": "Local AI", "settings.guide.loraAdapters.desc": "Manage local LoRA adapters that teach a model your writing voice.", "settings.guide.loraAdapters.title": "Fine-Tuning (LoRA)", "settings.guide.notifications.desc": "Reminders and desktop alerts.", @@ -2161,8 +2168,8 @@ "settings.language.hebrew": "Hebrew (beta)", "settings.language.italian": "Italian", "settings.language.japanese": "Japanese (beta)", - "settings.language.spanish": "Spanish", "settings.language.portuguese": "Portuguese (beta)", + "settings.language.spanish": "Spanish", "settings.language.title": "Language & Region", "settings.loraAdapters.deleteBtn": "Delete", "settings.loraAdapters.description": "Load LoRA fine-tuning adapters for local WebLLM models. Adapters are stored in your browser and never sent to the cloud.", @@ -2173,6 +2180,56 @@ "settings.loraAdapters.title": "LoRA Adapters", "settings.loraAdapters.uploadBtn": "Upload adapter (.safetensors / .bin)", "settings.loraAdapters.uploadError": "Failed to load adapter. The file may be invalid or too large.", + "settings.openRouter.apiKey": "API Key", + "settings.openRouter.apiKeyAriaLabel": "OpenRouter API key", + "settings.openRouter.apiKeyHint": "Stored encrypted on this device.", + "settings.openRouter.apiKeyPlaceholder": "sk-or-v1-…", + "settings.openRouter.circuitBreaker": "Circuit breaker:", + "settings.openRouter.circuitClosed": "Closed (healthy)", + "settings.openRouter.circuitOpen": "Open (paused 5 min)", + "settings.openRouter.clearKey": "Remove", + "settings.openRouter.customModelAriaLabel": "Custom model identifier", + "settings.openRouter.customModelLabel": "Custom model…", + "settings.openRouter.customModelPlaceholder": "deepseek/deepseek-r1:free", + "settings.openRouter.description": "Use OpenRouter as a unified cloud gateway. Free-tier models (marked with :free) need no paid credits.", + "settings.openRouter.enabled": "Enable OpenRouter", + "settings.openRouter.enabledHint": "When enabled, OpenRouter is preferred for cloud AI calls unless the active mode forbids cloud.", + "settings.openRouter.errors.generic": "An unexpected OpenRouter error occurred", + "settings.openRouter.freeModel.deepseekR1": "DeepSeek R1 (free)", + "settings.openRouter.freeModel.gemma327b": "Gemma 3 27B IT (free)", + "settings.openRouter.freeModel.llama3370b": "Llama 3.3 70B Instruct (free)", + "settings.openRouter.freeModel.mistral7b": "Mistral 7B Instruct (free)", + "settings.openRouter.freeModel.qwen2572b": "Qwen 2.5 72B Instruct (free)", + "settings.openRouter.freeTierNote": "Free-tier models: 20 req/min, 50 req/day without credits", + "settings.openRouter.getKeyLink": "Get a free API key at openrouter.ai/keys", + "settings.openRouter.keyError.empty": "Please enter an OpenRouter API key", + "settings.openRouter.keyError.invalid": "The API key appears invalid", + "settings.openRouter.keyError.network": "Network error while validating the key", + "settings.openRouter.keyError.saveFailed": "Failed to save the API key", + "settings.openRouter.keyStatus.removed": "API key removed", + "settings.openRouter.keyStatus.saved": "API key saved", + "settings.openRouter.keyStatus.saving": "Saving…", + "settings.openRouter.keyStatus.set": "Key stored — enter a new key to replace it", + "settings.openRouter.keyStatus.unset": "No API key stored", + "settings.openRouter.modeWarning.local": "OpenRouter is disabled while AI mode is set to local-only.", + "settings.openRouter.modeWarning.offline": "OpenRouter is paused because the device is offline.", + "settings.openRouter.modelAriaLabel": "Preferred OpenRouter model", + "settings.openRouter.modelFetch.empty": "No models found", + "settings.openRouter.modelFetch.failed": "Could not load model catalog", + "settings.openRouter.modelFetch.loading": "Loading model catalog…", + "settings.openRouter.modelPlaceholder": "Select or search a model", + "settings.openRouter.paidModelNote": "Paid models require credits on your OpenRouter account.", + "settings.openRouter.policyBlocked.localOnly": "OpenRouter is blocked because “Local storage only” is on. Turn it off in Privacy & Data to allow cloud AI.", + "settings.openRouter.policyBlocked.mode": "OpenRouter is unavailable while the AI mode is Local or Eco. Switch to Hybrid or Cloud in AI & Models to use it.", + "settings.openRouter.preferredModel": "Preferred Model", + "settings.openRouter.resetCircuit": "Reset", + "settings.openRouter.resetCircuitAria": "Reset OpenRouter circuit breaker", + "settings.openRouter.rpmLabel": "Requests / min (last 60 s)", + "settings.openRouter.saveKey": "Save", + "settings.openRouter.testConnection": "Test connection", + "settings.openRouter.testConnectionFailed": "Connection failed", + "settings.openRouter.testConnectionOk": "Connection successful", + "settings.openRouter.title": "OpenRouter", "settings.overview.openGuide": "Full settings guide", "settings.overview.title": "Quick links", "settings.plugins.description": "Manage WorldScript Studio extension plugins. Plugins run in a sandboxed API layer and can only access the permissions they declare.", @@ -2214,11 +2271,11 @@ "settings.privacy.encryptionUnlockButton": "Unlock", "settings.privacy.encryptionWarning": "If you forget your passphrase, your data cannot be recovered.", "settings.privacy.encryptionWrongPassphrase": "Wrong passphrase — decryption failed", + "settings.privacy.euDataResidency": "EU Data Residency", + "settings.privacy.euDataResidencyHint": "Keep all data within European Union servers where applicable.", "settings.privacy.localStorageOnly": "Local Storage Only", "settings.privacy.migrationComplete": "All data encrypted successfully", "settings.privacy.migrationProgress": "Encrypting existing data…", - "settings.privacy.euDataResidency": "EU Data Residency", - "settings.privacy.euDataResidencyHint": "Keep all data within European Union servers where applicable.", "settings.privacy.title": "Privacy & Security", "settings.projectAi.activeIndicator": "Project AI active", "settings.projectAi.category": "Project AI", @@ -2289,8 +2346,15 @@ "settings.voice.autoPunctuationHint": "Automatically add periods and commas while dictating.", "settings.voice.cloudFallback": "Allow Cloud STT Fallback", "settings.voice.cloudFallbackHint": "When local speech recognition is unavailable, send audio to cloud providers. Requires internet.", + "settings.voice.downloadModels": "Download Models", + "settings.voice.downloadSttModel": "Download STT (Whisper)", + "settings.voice.downloadTtsModel": "Download TTS (Kokoro)", "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", + "settings.voice.engine.auto": "Auto (recommended)", + "settings.voice.engine.privacyNote": "Privacy: ‘Web Speech API’ sends audio to your browser vendor (Google, Apple, or Microsoft). ‘Local WASM model’ runs fully on your device. ‘Auto’ prefers on-device and may fall back to cloud.", + "settings.voice.engine.wasm": "Local WASM model (offline)", + "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Control WorldScript Studio with your voice. Choose a cloud or fully on-device speech engine below.", "settings.voice.level.minimal": "Minimal — errors only", @@ -2305,91 +2369,33 @@ "settings.voice.privacy.consentDecline": "Decline", "settings.voice.privacy.consentTitle": "Web Speech Consent", "settings.voice.privacy.revokeConsent": "Revoke Consent", + "settings.voice.privacy.revokeConsentHint": "Removes your Web Speech consent. Voice will fall back to local WASM or be disabled.", "settings.voice.privacy.statusExternal": "External", "settings.voice.privacy.statusLocal": "Local", "settings.voice.privacyNotice": "By default, the Web Speech engine sends your audio to Google or Microsoft for transcription. Switch to the on-device (WASM) engine to keep all audio on your device.", + "settings.voice.pttHint": "Push-to-Talk shortcut: Ctrl+Shift+V (Windows/Linux) or ⌘+Shift+V (Mac). Hold to record.", + "settings.voice.speechRate": "Speech Rate", + "settings.voice.speechRateHint": "How fast the text-to-speech voice speaks. 1.0 = normal speed.", + "settings.voice.speechVolume": "Speech Volume", + "settings.voice.speechVolumeHint": "Volume of the text-to-speech voice. Does not affect microphone input.", + "settings.voice.sttEngine": "Speech Recognition (STT) Engine", + "settings.voice.sttEngineHint": "Choose the engine that converts your speech to text. 'Auto' picks the best available option.", "settings.voice.title": "Voice Full Support", + "settings.voice.ttsEngine": "Text-to-Speech (TTS) Engine", + "settings.voice.ttsEngineHint": "Choose the voice that reads responses aloud. 'Auto' picks the best available option.", "settings.voice.ttsMuted": "Mute All Speech Output", "settings.voice.ttsMutedHint": "Disable text-to-speech while keeping visual indicators.", + "settings.voice.wakeWordPhrase": "Wake Word Phrase", + "settings.voice.wakeWordPhraseHint": "The phrase you say to activate voice commands hands-free.", + "settings.voice.wasmModels": "WASM Voice Models", + "settings.voice.wasmModelsNotReady": "Whisper STT (~42 MB) and Kokoro TTS (~15 MB) models not downloaded", + "settings.voice.wasmModelsReady": "Downloaded and ready for local voice processing", "voice.modelDownload.cancel": "Cancel", "voice.modelDownload.description": "Downloading {{model}} model ({{size}} MB). This enables local voice processing without cloud routing.", "voice.modelDownload.error": "Download failed: {{error}}", "voice.modelDownload.progress": "{{percent}}% complete", "voice.modelDownload.retry": "Retry", "voice.modelDownload.title": "Voice Model Download", - "settings.voice.wasmModels": "WASM Voice Models", - "settings.voice.wasmModelsReady": "Downloaded and ready for local voice processing", - "settings.voice.wasmModelsNotReady": "Whisper STT (~42 MB) and Kokoro TTS (~15 MB) models not downloaded", - "settings.voice.downloadModels": "Download Models", - "settings.voice.downloadSttModel": "Download STT (Whisper)", - "settings.voice.downloadTtsModel": "Download TTS (Kokoro)", - "settings.voice.sttEngine": "Speech Recognition (STT) Engine", - "settings.voice.sttEngineHint": "Choose the engine that converts your speech to text. 'Auto' picks the best available option.", - "settings.voice.ttsEngine": "Text-to-Speech (TTS) Engine", - "settings.voice.ttsEngineHint": "Choose the voice that reads responses aloud. 'Auto' picks the best available option.", - "settings.voice.engine.auto": "Auto (recommended)", - "settings.voice.engine.webSpeech": "Web Speech API (cloud)", - "settings.voice.engine.wasm": "Local WASM model (offline)", - "settings.voice.engine.privacyNote": "Privacy: ‘Web Speech API’ sends audio to your browser vendor (Google, Apple, or Microsoft). ‘Local WASM model’ runs fully on your device. ‘Auto’ prefers on-device and may fall back to cloud.", - "settings.voice.speechRate": "Speech Rate", - "settings.voice.speechRateHint": "How fast the text-to-speech voice speaks. 1.0 = normal speed.", - "settings.voice.speechVolume": "Speech Volume", - "settings.voice.speechVolumeHint": "Volume of the text-to-speech voice. Does not affect microphone input.", - "settings.voice.wakeWordPhrase": "Wake Word Phrase", - "settings.voice.wakeWordPhraseHint": "The phrase you say to activate voice commands hands-free.", - "settings.voice.pttHint": "Push-to-Talk shortcut: Ctrl+Shift+V (Windows/Linux) or ⌘+Shift+V (Mac). Hold to record.", - "settings.voice.privacy.revokeConsentHint": "Removes your Web Speech consent. Voice will fall back to local WASM or be disabled.", - "settings.categories.localAi": "Local AI", - "settings.guide.localAi.title": "Local AI", - "settings.guide.localAi.desc": "Run the AI on your device — check capability, download models, manage storage, and review the offline fallback chain.", - "settings.ai.localAi.sectionTitle": "Local AI", - "settings.ai.localAi.sectionDescription": "Run inference on your device. No data leaves the browser. Capability, downloads, and storage are managed here.", - "settings.ai.localAi.webgpuLabel": "WebGPU", - "settings.ai.localAi.webgpuAvailable": "Available", - "settings.ai.localAi.webgpuUnavailable": "Not available", - "settings.ai.localAi.deviceClassLabel": "Device class", - "settings.ai.localAi.recommendedModel": "Recommended for your device: {{model}}", - "settings.ai.localAi.onboardingHint": "No local model downloaded yet. Download one below to enable offline AI — the first download may take a few minutes.", - "settings.ai.localAi.modelsTitle": "Models", - "settings.ai.localAi.modelsDescription": "Download a model to use it offline. Larger models are higher quality but need more storage and a capable GPU.", - "settings.ai.localAi.downloadButton": "Download", - "settings.ai.localAi.downloadingButton": "Downloading…", - "settings.ai.localAi.readyBadge": "Ready", - "settings.ai.localAi.sizeWarning": "Needs ~{{size}} MB; only {{free}} MB free", - "settings.ai.localAi.modelReadyAnnounce": "{{model}} is ready for offline use", - "settings.ai.localAi.requiresGpuNote": "Without WebGPU, models run on a slower CPU/WASM fallback or download may be unavailable.", - "settings.ai.localAi.storageTitle": "Storage", - "settings.ai.localAi.storageUsage": "{{used}} MB of {{quota}} MB used ({{percent}}%)", - "settings.ai.localAi.storageModelsCached": "{{count}} local model cache(s) on disk", - "settings.ai.localAi.storageUnsupported": "Storage estimates are not available in this browser.", - "settings.ai.localAi.storageAriaLabel": "Local storage usage", - "settings.ai.localAi.clearButton": "Clear Local Models", - "settings.ai.localAi.clearingButton": "Clearing…", - "settings.ai.localAi.clearConfirm": "Delete all downloaded local models? They will re-download the next time you use local AI.", - "settings.ai.localAi.clearConfirmYes": "Delete models", - "settings.ai.localAi.clearCancel": "Cancel", - "settings.ai.localAi.clearedAnnounce": "Cleared {{count}} local model cache(s)", - "settings.ai.localAi.fallbackTitle": "Fallback chain", - "settings.ai.localAi.fallbackIntro": "When a layer is unavailable, the Co-Pilot automatically tries the next one:", - "settings.ai.localAi.fallbackLayer1": "WebGPU (WebLLM) — fastest and highest quality; needs a capable GPU.", - "settings.ai.localAi.fallbackLayer2": "WASM (ONNX) — runs on the CPU when no GPU is available.", - "settings.ai.localAi.fallbackLayer3": "Transformers.js — lightweight last-resort generator.", - "settings.ai.localAi.fallbackLayer4": "Heuristic — always-available offline stub when no model can run.", - "settings.ai.localAi.perfThroughput": "Last local run: {{tps}} tokens/sec", - "settings.ai.localAi.perfNoData": "Download and run a model to measure throughput.", - "settings.ai.localAi.docsLink": "Local AI setup & troubleshooting", - "settings.ai.localAi.detecting": "Detecting…", - "settings.ai.localAi.clearBusy": "Local AI is busy right now — try clearing again once it finishes.", - "settings.ai.localAi.downloadFailed": "Download failed. Please try again.", - "settings.ai.localAi.clearFailed": "Could not clear local models. Please try again.", - "settings.ai.localAi.modelLabel.qwen25_05b": "Qwen 2.5 0.5B (eco, ~0.4 GB)", - "settings.ai.localAi.modelLabel.llama32_1b": "Llama 3.2 1B (fast, ~0.7 GB)", - "settings.ai.localAi.modelLabel.llama32_3b": "Llama 3.2 3B (~1.8 GB)", - "settings.ai.localAi.modelLabel.phi4mini": "Phi-4 Mini 3.8B (~2.3 GB)", - "settings.ai.localAi.modelLabel.gemma3_1b": "Gemma 3 1B (~0.8 GB)", - "settings.ai.localAi.modelLabel.gemma3_4b": "Gemma 3 4B (~4.9 GB)", - "settings.ai.localAi.modelLabel.llama33_70b": "Llama 3.3 70B (high-end, ~35 GB)", - "settings.about.productName": "WorldScript Studio", "sidebar.mainAria": "Main sidebar", "sidebar.primaryNavAria": "Primary navigation", "sidebar.secondaryNavAria": "Settings and help", diff --git a/public/locales/es/bundle.json b/public/locales/es/bundle.json index e37193d9..fba0fc79 100644 --- a/public/locales/es/bundle.json +++ b/public/locales/es/bundle.json @@ -1621,6 +1621,7 @@ "settings.about.githubDescription": "Ver el código fuente, reportar errores y contribuir.", "settings.about.githubLabel": "Código abierto en GitHub", "settings.about.liveDemo": "Probar la demo en vivo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Versión del runtime de escritorio", "settings.about.title": "Acerca de WorldScript Studio", "settings.about.versionLabel": "Versión", @@ -1671,16 +1672,16 @@ "settings.advancedAi.model": "Modelo de IA", "settings.advancedAi.modelDescription": "El modelo de IA usado para generación de escenas, análisis y otras funciones. La disponibilidad depende del proveedor seleccionado.", "settings.advancedAi.modelRecommendationsIntro": "Puntos de control locales populares (verifica los nombres en tu entorno de ejecución):", - "settings.advancedAi.ollamaPull.recommendedFor": "Recomendado para tu dispositivo:", + "settings.advancedAi.ollamaPull.batteryNote": "Se eligió un tamaño menor para ahorrar batería.", + "settings.advancedAi.ollamaPull.installed": "Instalado", "settings.advancedAi.ollamaPull.pull": "Descargar modelo", "settings.advancedAi.ollamaPull.pulling": "Descargando modelo…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recomendado para tu dispositivo:", "settings.advancedAi.ollamaPull.retry": "Reintentar", - "settings.advancedAi.ollamaPull.installed": "Instalado", - "settings.advancedAi.ollamaPull.useModel": "Usar este modelo", - "settings.advancedAi.ollamaPull.batteryNote": "Se eligió un tamaño menor para ahorrar batería.", "settings.advancedAi.ollamaPull.tier.high-end": "Gama alta", - "settings.advancedAi.ollamaPull.tier.mid-range": "Gama media", "settings.advancedAi.ollamaPull.tier.low-end": "Gama baja", + "settings.advancedAi.ollamaPull.tier.mid-range": "Gama media", + "settings.advancedAi.ollamaPull.useModel": "Usar este modelo", "settings.advancedAi.ragModeHint": "El modo híbrido combina búsqueda por palabras clave con comprensión semántica — ideal para la mayoría de historias. Reconstruye el índice tras grandes cambios.", "settings.advancedAi.ragModeHybrid": "Híbrido (semántico + léxico, recomendado)", "settings.advancedAi.ragModeLabel": "Modo de recuperación de contexto", @@ -1729,6 +1730,7 @@ "settings.ai.creativity": "Nivel de creatividad de la IA", "settings.ai.creativityDescription": "Los valores más altos producen resultados más inesperados.", "settings.ai.customModel": "Modelo personalizado", + "settings.ai.downloadDesktopCta": "Descargar la aplicación de escritorio", "settings.ai.fallbackNone": "Ninguno", "settings.ai.fallbackStep1": "Primer respaldo", "settings.ai.fallbackStep2": "Segundo respaldo", @@ -1812,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "No disponible", "settings.ai.localBackendPreset": "Preajuste de backend local", "settings.ai.ollamaBrowserNote": "Ollama solo está disponible en la aplicación de escritorio. La política de seguridad de contenido del navegador bloquea las conexiones directas a localhost.", - "settings.ai.ollamaHint": "Asegúrate de que ollama serve está en ejecución y CORS está habilitado.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama y los servidores locales compatibles con OpenAI (LM Studio, vLLM) solo están disponibles en la aplicación de escritorio. Los navegadores bloquean las conexiones directas a localhost (Content Security Policy y Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Se requiere la aplicación de escritorio para servidores locales", + "settings.ai.ollamaHint": "Asegúrate de que el servidor esté en ejecución (p. ej. ollama serve). La aplicación de escritorio se conecta directamente, sin configuración CORS.", "settings.ai.ollamaModelHint": "Selección rápida de modelos reportados por tu servidor — toca para usar.", "settings.ai.ollamaServerUrl": "URL del servidor Ollama", "settings.ai.ollamaTauriBypass": "Versión de escritorio: WorldScript llama a Ollama directamente — sin barrera de CORS del navegador.", @@ -1844,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Escanear puertos locales comunes", "settings.ai.scanNo": "sin respuesta", "settings.ai.scanOk": "accesible", + "settings.ai.scanStateHttp": "error HTTP", + "settings.ai.scanStateTimeout": "tiempo de espera agotado", + "settings.ai.scanUseUrl": "Usar esta URL", "settings.ai.temperature.balanced": "1 – Equilibrado", "settings.ai.temperature.creative": "2 – Creativo", "settings.ai.temperature.precise": "0 – Preciso", @@ -2043,24 +2050,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Vista previa en vivo", "settings.editor.title": "Preferencias del editor", - "settings.featureFlags.description": "Prueba funciones que aún estamos refinando. Tu opinión define lo que publicamos.", - "settings.featureFlags.category.core": "Escritura", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Flujo de edición", - "settings.featureFlags.category.personalization": "Personalización", "settings.featureFlags.category.analytics": "Analíticas", - "settings.featureFlags.category.performance": "Rendimiento", - "settings.featureFlags.category.voice": "Voz", + "settings.featureFlags.category.core": "Escritura", "settings.featureFlags.category.extensions": "Extensiones", - "settings.featureFlags.category.sync": "Sincronización", "settings.featureFlags.category.i18n": "Idioma y diseño", - "settings.featureFlags.dependency.requires": "Requiere {{name}}", + "settings.featureFlags.category.performance": "Rendimiento", + "settings.featureFlags.category.personalization": "Personalización", + "settings.featureFlags.category.pipeline": "Flujo de edición", + "settings.featureFlags.category.sync": "Sincronización", + "settings.featureFlags.category.voice": "Voz", "settings.featureFlags.dependency.desktopOnly": "Solo en la app de escritorio", - "settings.featureFlags.risk.high": "Puede usar mucha memoria, GPU o presupuesto de tokens.", - "settings.featureFlags.resetToDefaults": "Restablecer valores predeterminados", - "settings.featureFlags.resetTitle": "¿Restablecer las funciones experimentales?", - "settings.featureFlags.resetConfirm": "Esto restaura todas las funciones experimentales a su estado predeterminado (activado/desactivado). Tus proyectos y contenido no se ven afectados.", - "settings.featureFlags.resetDone": "Funciones experimentales restablecidas a los valores predeterminados.", + "settings.featureFlags.dependency.requires": "Requiere {{name}}", + "settings.featureFlags.description": "Prueba funciones que aún estamos refinando. Tu opinión define lo que publicamos.", "settings.featureFlags.enableAdaptiveAiEngine": "Motor IA adaptativo (selección inteligente de backend)", "settings.featureFlags.enableAppHealthPanel": "Instantánea del estado de la app (acerca de)", "settings.featureFlags.enableBinderResearch": "Cuaderno de investigación (barra lateral del manuscrito)", @@ -2083,6 +2085,11 @@ "settings.featureFlags.enableVoiceSupport": "Comandos de voz y dictado", "settings.featureFlags.enableVoiceWasm": "Motor de voz WASM (Whisper.cpp — sin conexión)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orquestación tipada de trabajadores — Fase 2)", + "settings.featureFlags.resetConfirm": "Esto restaura todas las funciones experimentales a su estado predeterminado (activado/desactivado). Tus proyectos y contenido no se ven afectados.", + "settings.featureFlags.resetDone": "Funciones experimentales restablecidas a los valores predeterminados.", + "settings.featureFlags.resetTitle": "¿Restablecer las funciones experimentales?", + "settings.featureFlags.resetToDefaults": "Restablecer valores predeterminados", + "settings.featureFlags.risk.high": "Puede usar mucha memoria, GPU o presupuesto de tokens.", "settings.featureFlags.title": "Funciones de acceso anticipado", "settings.font.custom": "Fuente personalizada", "settings.font.mono": "Monoespaciado", @@ -2212,8 +2219,8 @@ "settings.openRouter.modelFetch.loading": "Cargando catálogo de modelos…", "settings.openRouter.modelPlaceholder": "Selecciona o busca un modelo", "settings.openRouter.paidModelNote": "Los modelos de pago requieren créditos en tu cuenta de OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter no está disponible en el modo de IA Local o Eco. Cambia a Híbrido o Nube en IA y Modelos para usarlo.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter está bloqueado porque “Solo almacenamiento local” está activado. Desáctivalo en Privacidad y Datos para permitir la IA en la nube.", + "settings.openRouter.policyBlocked.mode": "OpenRouter no está disponible en el modo de IA Local o Eco. Cambia a Híbrido o Nube en IA y Modelos para usarlo.", "settings.openRouter.preferredModel": "Modelo preferido", "settings.openRouter.resetCircuit": "Restablecer", "settings.openRouter.resetCircuitAria": "Restablecer el cortacircuitos de OpenRouter", @@ -2345,8 +2352,8 @@ "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", "settings.voice.engine.auto": "Automático (recomendado)", - "settings.voice.engine.wasm": "Modelo WASM local (sin conexión)", "settings.voice.engine.privacyNote": "Privacidad: «Web Speech API» envía audio al proveedor de tu navegador (Google, Apple o Microsoft). «Modelo WASM local» se ejecuta totalmente en tu dispositivo. «Auto» prefiere local y puede recurrir a la nube.", + "settings.voice.engine.wasm": "Modelo WASM local (sin conexión)", "settings.voice.engine.webSpeech": "Web Speech API (nube)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Controla WorldScript Studio con tu voz. Elige abajo un motor de voz en la nube o totalmente local.", @@ -2389,7 +2396,6 @@ "voice.modelDownload.progress": "{{percent}}% completado", "voice.modelDownload.retry": "Reintentar", "voice.modelDownload.title": "Descarga de modelo de voz", - "settings.about.productName": "WorldScript Studio", "sidebar.characterGraph": "Grafo de personajes", "sidebar.characterInterviews": "Entrevistas de personajes", "sidebar.characters": "Personajes", diff --git a/public/locales/eu/bundle.json b/public/locales/eu/bundle.json index 7ce35d64..44f4d84d 100644 --- a/public/locales/eu/bundle.json +++ b/public/locales/eu/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AI Sormen Maila", "settings.ai.creativityDescription": "Balio altuagoek ustekabeko emaitza gehiago sortzen dituzte.", "settings.ai.customModel": "Eredu pertsonalizatua", + "settings.ai.downloadDesktopCta": "Deskargatu mahaigaineko aplikazioa", "settings.ai.fallbackNone": "Bat ere ez", "settings.ai.fallbackStep1": "Lehenengo atzerakada", "settings.ai.fallbackStep2": "Bigarren atzerakada", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ez dago eskuragarri", "settings.ai.localBackendPreset": "Backend lokala aurrez ezarri", "settings.ai.ollamaBrowserNote": "Ollama mahaigaineko aplikazioan bakarrik dago eskuragarri. Arakatzailearen Edukiaren Segurtasun-Politikak lokaleko ostalari konexio zuzenak blokeatzen ditu.", - "settings.ai.ollamaHint": "Ziurtatu ollama zerbitzaria martxan dagoela eta CORS gaituta dagoela.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama eta OpenAI-rekin bateragarriak diren tokiko zerbitzariak (LM Studio, vLLM) mahaigaineko aplikazioan bakarrik daude eskuragarri. Nabigatzaileek localhost-era zuzeneko konexioak blokeatzen dituzte (Edukiaren Segurtasun Politika eta Sare Pribaturako Sarbidea).", + "settings.ai.ollamaDesktopOnlyTitle": "Mahaigaineko aplikazioa behar da tokiko zerbitzarietarako", + "settings.ai.ollamaHint": "Ziurtatu zerbitzaria martxan dagoela (adib. ollama serve). Mahaigaineko aplikazioa zuzenean konektatzen da — ez da CORS konfiguraziorik behar.", "settings.ai.ollamaModelHint": "Aukeratu azkar zure zerbitzariak jakinarazitako ereduak — sakatu erabiltzeko.", "settings.ai.ollamaServerUrl": "Ollama zerbitzariaren URLa", "settings.ai.ollamaTauriBypass": "Mahaigaineko eraikuntza: WorldScript-ek zuzenean deitzen dio Ollamari — ez dago arakatzailearen CORS oztoporik.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Eskaneatu tokiko ataka arruntak", "settings.ai.scanNo": "erantzunik ez", "settings.ai.scanOk": "irisgarria", + "settings.ai.scanStateHttp": "HTTP errorea", + "settings.ai.scanStateTimeout": "denbora-muga gaindituta", + "settings.ai.scanUseUrl": "Erabili URL hau", "settings.ai.temperature.balanced": "1 – Orekatua", "settings.ai.temperature.creative": "2 – Sormena", "settings.ai.temperature.precise": "0 – Zehatza", diff --git a/public/locales/fa/bundle.json b/public/locales/fa/bundle.json index 7442ea6a..a1259f71 100644 --- a/public/locales/fa/bundle.json +++ b/public/locales/fa/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "سطح خلاقیت هوش مصنوعی", "settings.ai.creativityDescription": "مقادیر بالاتر نتایج غیرمنتظره تری ایجاد می کند.", "settings.ai.customModel": "مدل سفارشی", + "settings.ai.downloadDesktopCta": "دانلود برنامه دسکتاپ", "settings.ai.fallbackNone": "هیچ کدام", "settings.ai.fallbackStep1": "اولین بازگشت", "settings.ai.fallbackStep2": "بازگشت دوم", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "در دسترس نیست", "settings.ai.localBackendPreset": "از پیش تنظیم شده باطن محلی", "settings.ai.ollamaBrowserNote": "Ollama فقط در برنامه دسکتاپ در دسترس است. خط مشی امنیت محتوای مرورگر اتصال مستقیم به لوکال هاست را مسدود می کند.", - "settings.ai.ollamaHint": "مطمئن شوید که سرویس olama در حال اجرا است و CORS فعال است.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama و سرورهای محلی سازگار با OpenAI (LM Studio، vLLM) فقط در برنامه دسکتاپ در دسترس هستند. مرورگرها اتصالات مستقیم به localhost را مسدود می‌کنند (سیاست امنیت محتوا و دسترسی به شبکه خصوصی).", + "settings.ai.ollamaDesktopOnlyTitle": "برنامه دسکتاپ برای سرورهای محلی لازم است", + "settings.ai.ollamaHint": "مطمئن شوید سرور در حال اجراست (مثلاً ollama serve). برنامه دسکتاپ مستقیم متصل می‌شود — نیازی به تنظیم CORS نیست.", "settings.ai.ollamaModelHint": "مدل‌های گزارش‌شده توسط سرورتان را سریع انتخاب کنید — برای استفاده ضربه بزنید.", "settings.ai.ollamaServerUrl": "آدرس سرور اوللاما", "settings.ai.ollamaTauriBypass": "ساخت دسکتاپ: WorldScript مستقیماً اوللاما را فرا می‌خواند - بدون مانع CORS مرورگر.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "پورت های محلی رایج را اسکن کنید", "settings.ai.scanNo": "بدون پاسخ", "settings.ai.scanOk": "قابل دسترس", + "settings.ai.scanStateHttp": "خطای HTTP", + "settings.ai.scanStateTimeout": "پایان مهلت", + "settings.ai.scanUseUrl": "استفاده از این نشانی", "settings.ai.temperature.balanced": "1- متعادل", "settings.ai.temperature.creative": "2- خلاق", "settings.ai.temperature.precise": "0 - دقیق", diff --git a/public/locales/fi/bundle.json b/public/locales/fi/bundle.json index 0cce6112..7446ae77 100644 --- a/public/locales/fi/bundle.json +++ b/public/locales/fi/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "Tekoälyn luovuustaso", "settings.ai.creativityDescription": "Suuremmat arvot tuottavat enemmän odottamattomia tuloksia.", "settings.ai.customModel": "Mukautettu malli", + "settings.ai.downloadDesktopCta": "Lataa työpöytäsovellus", "settings.ai.fallbackNone": "Ei mitään", "settings.ai.fallbackStep1": "Ensimmäinen takaisku", "settings.ai.fallbackStep2": "Toinen takaisku", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ei saatavilla", "settings.ai.localBackendPreset": "Paikallinen taustajärjestelmän esiasetus", "settings.ai.ollamaBrowserNote": "Ollama on saatavilla vain työpöytäsovelluksessa. Selaimen sisällön suojauskäytäntö estää suorat yhteydet localhostiin.", - "settings.ai.ollamaHint": "Varmista, että ollama-palvelu on käynnissä ja CORS on käytössä.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama ja paikalliset OpenAI-yhteensopivat palvelimet (LM Studio, vLLM) ovat käytettävissä vain työpöytäsovelluksessa. Selaimet estävät suorat yhteydet localhostiin (Content Security Policy ja Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Paikalliset palvelimet vaativat työpöytäsovelluksen", + "settings.ai.ollamaHint": "Varmista, että palvelin on käynnissä (esim. ollama serve). Työpöytäsovellus yhdistää suoraan — CORS-asetuksia ei tarvita.", "settings.ai.ollamaModelHint": "Palvelimesi ilmoittamat pikavalintamallit – käytä napauttamalla.", "settings.ai.ollamaServerUrl": "Ollama-palvelimen URL-osoite", "settings.ai.ollamaTauriBypass": "Työpöytärakenne: WorldScript kutsuu Ollamaa suoraan – ei selaimen CORS-estettä.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Tarkista yleiset paikalliset portit", "settings.ai.scanNo": "ei vastausta", "settings.ai.scanOk": "tavoitettavissa", + "settings.ai.scanStateHttp": "HTTP-virhe", + "settings.ai.scanStateTimeout": "aikakatkaisu", + "settings.ai.scanUseUrl": "Käytä tätä URL-osoitetta", "settings.ai.temperature.balanced": "1 – Tasapainoinen", "settings.ai.temperature.creative": "2 – Luova", "settings.ai.temperature.precise": "0 – Tarkka", diff --git a/public/locales/fr/bundle.json b/public/locales/fr/bundle.json index 30e7dc36..41506bd1 100644 --- a/public/locales/fr/bundle.json +++ b/public/locales/fr/bundle.json @@ -1621,6 +1621,7 @@ "settings.about.githubDescription": "Voir le code source, signaler des bugs et contribuer.", "settings.about.githubLabel": "Open-source sur GitHub", "settings.about.liveDemo": "Essayer la démo en ligne", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Version du runtime bureau", "settings.about.title": "À propos de WorldScript Studio", "settings.about.versionLabel": "Version", @@ -1671,16 +1672,16 @@ "settings.advancedAi.model": "Modèle d'IA", "settings.advancedAi.modelDescription": "Le modèle IA utilisé pour la génération de scènes, l'analyse et d'autres fonctionnalités IA. La disponibilité dépend du fournisseur sélectionné.", "settings.advancedAi.modelRecommendationsIntro": "Points de contrôle locaux populaires (vérifiez les noms dans votre environnement d'exécution) :", - "settings.advancedAi.ollamaPull.recommendedFor": "Recommandé pour votre appareil :", + "settings.advancedAi.ollamaPull.batteryNote": "Taille réduite pour économiser la batterie.", + "settings.advancedAi.ollamaPull.installed": "Installé", "settings.advancedAi.ollamaPull.pull": "Télécharger le modèle", "settings.advancedAi.ollamaPull.pulling": "Téléchargement du modèle…", + "settings.advancedAi.ollamaPull.recommendedFor": "Recommandé pour votre appareil :", "settings.advancedAi.ollamaPull.retry": "Réessayer", - "settings.advancedAi.ollamaPull.installed": "Installé", - "settings.advancedAi.ollamaPull.useModel": "Utiliser ce modèle", - "settings.advancedAi.ollamaPull.batteryNote": "Taille réduite pour économiser la batterie.", "settings.advancedAi.ollamaPull.tier.high-end": "Haut de gamme", - "settings.advancedAi.ollamaPull.tier.mid-range": "Milieu de gamme", "settings.advancedAi.ollamaPull.tier.low-end": "Entrée de gamme", + "settings.advancedAi.ollamaPull.tier.mid-range": "Milieu de gamme", + "settings.advancedAi.ollamaPull.useModel": "Utiliser ce modèle", "settings.advancedAi.ragModeHint": "Le mode hybride associe recherche par mots-clés et compréhension sémantique — idéal pour la plupart des histoires. Reconstruisez l'index après de grandes modifications.", "settings.advancedAi.ragModeHybrid": "Hybride (sémantique + lexical, recommandé)", "settings.advancedAi.ragModeLabel": "Mode de récupération du contexte", @@ -1729,6 +1730,7 @@ "settings.ai.creativity": "Niveau de créativité de l'IA", "settings.ai.creativityDescription": "Des valeurs plus élevées produisent des résultats plus inattendus.", "settings.ai.customModel": "Modèle personnalisé", + "settings.ai.downloadDesktopCta": "Télécharger l'application de bureau", "settings.ai.fallbackNone": "Aucun", "settings.ai.fallbackStep1": "Premier repli", "settings.ai.fallbackStep2": "Deuxième repli", @@ -1812,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Indisponible", "settings.ai.localBackendPreset": "Préréglage backend local", "settings.ai.ollamaBrowserNote": "Ollama n'est disponible que dans l'application de bureau. La politique de sécurité du contenu du navigateur bloque les connexions directes à localhost.", - "settings.ai.ollamaHint": "Assurez-vous qu'ollama serve est en cours d'exécution et que CORS est activé.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama et les serveurs locaux compatibles OpenAI (LM Studio, vLLM) ne sont disponibles que dans l'application de bureau. Les navigateurs bloquent les connexions directes vers localhost (Content Security Policy et Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Application de bureau requise pour les serveurs locaux", + "settings.ai.ollamaHint": "Assurez-vous que le serveur est en cours d'exécution (p. ex. ollama serve). L'application de bureau se connecte directement — aucune configuration CORS nécessaire.", "settings.ai.ollamaModelHint": "Sélection rapide des modèles rapportés par votre serveur — appuyez pour utiliser.", "settings.ai.ollamaServerUrl": "URL du serveur Ollama", "settings.ai.ollamaTauriBypass": "Version bureau : WorldScript appelle Ollama directement — aucune barrière CORS du navigateur.", @@ -1844,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Scanner les ports locaux courants", "settings.ai.scanNo": "pas de réponse", "settings.ai.scanOk": "accessible", + "settings.ai.scanStateHttp": "erreur HTTP", + "settings.ai.scanStateTimeout": "délai dépassé", + "settings.ai.scanUseUrl": "Utiliser cette URL", "settings.ai.temperature.balanced": "1 – Équilibré", "settings.ai.temperature.creative": "2 – Créatif", "settings.ai.temperature.precise": "0 – Précis", @@ -2043,24 +2050,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Aperçu en direct", "settings.editor.title": "Préférences de l'éditeur", - "settings.featureFlags.description": "Essayez des fonctionnalités que nous affinons encore. Vos retours façonnent ce qui sera publié.", - "settings.featureFlags.category.core": "Écriture", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Chaîne d'édition", - "settings.featureFlags.category.personalization": "Personnalisation", "settings.featureFlags.category.analytics": "Analyses", - "settings.featureFlags.category.performance": "Performances", - "settings.featureFlags.category.voice": "Voix", + "settings.featureFlags.category.core": "Écriture", "settings.featureFlags.category.extensions": "Extensions", - "settings.featureFlags.category.sync": "Synchronisation", "settings.featureFlags.category.i18n": "Langue et mise en page", - "settings.featureFlags.dependency.requires": "Nécessite {{name}}", + "settings.featureFlags.category.performance": "Performances", + "settings.featureFlags.category.personalization": "Personnalisation", + "settings.featureFlags.category.pipeline": "Chaîne d'édition", + "settings.featureFlags.category.sync": "Synchronisation", + "settings.featureFlags.category.voice": "Voix", "settings.featureFlags.dependency.desktopOnly": "Application de bureau uniquement", - "settings.featureFlags.risk.high": "Peut utiliser beaucoup de mémoire, de GPU ou de budget de jetons.", - "settings.featureFlags.resetToDefaults": "Réinitialiser par défaut", - "settings.featureFlags.resetTitle": "Réinitialiser les fonctionnalités expérimentales ?", - "settings.featureFlags.resetConfirm": "Cela rétablit toutes les fonctionnalités expérimentales à leur état par défaut (activé/désactivé). Vos projets et votre contenu ne sont pas affectés.", - "settings.featureFlags.resetDone": "Fonctionnalités expérimentales réinitialisées par défaut.", + "settings.featureFlags.dependency.requires": "Nécessite {{name}}", + "settings.featureFlags.description": "Essayez des fonctionnalités que nous affinons encore. Vos retours façonnent ce qui sera publié.", "settings.featureFlags.enableAdaptiveAiEngine": "Moteur IA adaptatif (sélection intelligente du backend)", "settings.featureFlags.enableAppHealthPanel": "Instantané de l'état de l'application (à propos)", "settings.featureFlags.enableBinderResearch": "Classeur de recherche (barre latérale du manuscrit)", @@ -2083,6 +2085,11 @@ "settings.featureFlags.enableVoiceSupport": "Commandes vocales & dictée", "settings.featureFlags.enableVoiceWasm": "Moteur vocal WASM (Whisper.cpp — hors ligne)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orchestration typée de workers — Phase 2)", + "settings.featureFlags.resetConfirm": "Cela rétablit toutes les fonctionnalités expérimentales à leur état par défaut (activé/désactivé). Vos projets et votre contenu ne sont pas affectés.", + "settings.featureFlags.resetDone": "Fonctionnalités expérimentales réinitialisées par défaut.", + "settings.featureFlags.resetTitle": "Réinitialiser les fonctionnalités expérimentales ?", + "settings.featureFlags.resetToDefaults": "Réinitialiser par défaut", + "settings.featureFlags.risk.high": "Peut utiliser beaucoup de mémoire, de GPU ou de budget de jetons.", "settings.featureFlags.title": "Fonctionnalités en accès anticipé", "settings.font.custom": "Police personnalisée", "settings.font.mono": "Monospace", @@ -2212,8 +2219,8 @@ "settings.openRouter.modelFetch.loading": "Chargement du catalogue de modèles…", "settings.openRouter.modelPlaceholder": "Sélectionner ou rechercher un modèle", "settings.openRouter.paidModelNote": "Les modèles payants nécessitent des crédits sur votre compte OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter est indisponible en mode IA Local ou Éco. Passez en mode Hybride ou Cloud dans IA et Modèles pour l’utiliser.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter est bloqué car « Stockage local uniquement » est activé. Désactivez-le dans Confidentialité et Données pour autoriser l’IA cloud.", + "settings.openRouter.policyBlocked.mode": "OpenRouter est indisponible en mode IA Local ou Éco. Passez en mode Hybride ou Cloud dans IA et Modèles pour l’utiliser.", "settings.openRouter.preferredModel": "Modèle préféré", "settings.openRouter.resetCircuit": "Réinitialiser", "settings.openRouter.resetCircuitAria": "Réinitialiser le disjoncteur OpenRouter", @@ -2345,8 +2352,8 @@ "settings.voice.enableHint": "Activate voice commands, dictation, and audio feedback.", "settings.voice.enableLabel": "Enable Voice Support", "settings.voice.engine.auto": "Automatique (recommandé)", - "settings.voice.engine.wasm": "Modèle WASM local (hors ligne)", "settings.voice.engine.privacyNote": "Confidentialité : « Web Speech API » envoie l'audio à l'éditeur de votre navigateur (Google, Apple ou Microsoft). « Modèle WASM local » s'exécute entièrement sur votre appareil. « Auto » privilégie le local et peut basculer vers le cloud.", + "settings.voice.engine.wasm": "Modèle WASM local (hors ligne)", "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Audio Feedback Level", "settings.voice.intro": "Contrôlez WorldScript Studio à la voix. Choisissez ci-dessous un moteur vocal cloud ou entièrement local.", @@ -2389,7 +2396,6 @@ "voice.modelDownload.progress": "{{percent}}% terminé", "voice.modelDownload.retry": "Réessayer", "voice.modelDownload.title": "Téléchargement du modèle vocal", - "settings.about.productName": "WorldScript Studio", "sidebar.characterGraph": "Graphe des personnages", "sidebar.characterInterviews": "Entretiens de personnages", "sidebar.characters": "Personnages", diff --git a/public/locales/he/bundle.json b/public/locales/he/bundle.json index a3208eaa..0969a441 100644 --- a/public/locales/he/bundle.json +++ b/public/locales/he/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "רמת יצירתיות AI", "settings.ai.creativityDescription": "ערכים גבוהים מפיקים תוצאות בלתי צפויות יותר.", "settings.ai.customModel": "מודל מותאם", + "settings.ai.downloadDesktopCta": "הורדת יישום שולחן העבודה", "settings.ai.fallbackNone": "ללא", "settings.ai.fallbackStep1": "חלופה ראשונה", "settings.ai.fallbackStep2": "חלופה שנייה", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Not available", "settings.ai.localBackendPreset": "הגדרה מוגדרת מראש של מנוע אחורי מקומי", "settings.ai.ollamaBrowserNote": "‏Ollama זמין רק באפליקציית שולחן העבודה. מדיניות אבטחת התוכן של הדפדפן חוסמת חיבורים ישירים ל‑localhost.", - "settings.ai.ollamaHint": "ודאו ש‑ollama serve פועל ו‑CORS מופעל.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama ושרתים מקומיים תואמי-OpenAI (LM Studio, vLLM) זמינים רק ביישום שולחן העבודה. דפדפנים חוסמים חיבורים ישירים אל localhost (Content Security Policy ו-Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "נדרש יישום שולחני עבור שרתים מקומיים", + "settings.ai.ollamaHint": "ודא שהשרת פועל (למשל ollama serve). יישום שולחן העבודה מתחבר ישירות — אין צורך בהגדרת CORS.", "settings.ai.ollamaModelHint": "מודלי בחירה מהירה שדווחו על ידי השרת שלכם — הקישו לשימוש.", "settings.ai.ollamaServerUrl": "כתובת שרת Ollama", "settings.ai.ollamaTauriBypass": "בניית שולחן עבודה: WorldScript קורא ל‑Ollama ישירות — ללא מחסום CORS של הדפדפן.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "סריקת פורטים מקומיים נפוצים", "settings.ai.scanNo": "אין תגובה", "settings.ai.scanOk": "נגיש", + "settings.ai.scanStateHttp": "שגיאת HTTP", + "settings.ai.scanStateTimeout": "פג תוקף", + "settings.ai.scanUseUrl": "השתמש בכתובת זו", "settings.ai.temperature.balanced": "1 – מאוזן", "settings.ai.temperature.creative": "2 – יצירתי", "settings.ai.temperature.precise": "0 – מדויק", diff --git a/public/locales/hu/bundle.json b/public/locales/hu/bundle.json index 58058abc..5b77efed 100644 --- a/public/locales/hu/bundle.json +++ b/public/locales/hu/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AI kreativitás szintje", "settings.ai.creativityDescription": "A magasabb értékek váratlanabb eredményeket eredményeznek.", "settings.ai.customModel": "Egyedi modell", + "settings.ai.downloadDesktopCta": "Asztali alkalmazás letöltése", "settings.ai.fallbackNone": "Egyik sem", "settings.ai.fallbackStep1": "Első visszaesés", "settings.ai.fallbackStep2": "Második visszaesés", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Nem elérhető", "settings.ai.localBackendPreset": "Helyi háttér előre beállított", "settings.ai.ollamaBrowserNote": "Az Ollama csak az asztali alkalmazásban érhető el. A böngésző tartalombiztonsági házirendje blokkolja a közvetlen kapcsolatot a localhosttal.", - "settings.ai.ollamaHint": "Győződjön meg arról, hogy az ollama szolgáltatás fut, és a CORS engedélyezve van.", + "settings.ai.ollamaDesktopOnlyBody": "Az Ollama és a helyi OpenAI-kompatibilis kiszolgálók (LM Studio, vLLM) csak az asztali alkalmazásban érhetők el. A böngészők blokkolják a localhost felé irányuló közvetlen kapcsolatokat (Content Security Policy és Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Helyi kiszolgálókhoz asztali alkalmazás szükséges", + "settings.ai.ollamaHint": "Győződj meg róla, hogy a kiszolgáló fut (pl. ollama serve). Az asztali alkalmazás közvetlenül kapcsolódik — CORS-beállítás nem szükséges.", "settings.ai.ollamaModelHint": "A kiszolgáló által jelentett modellek gyors kiválasztása – koppintson a használathoz.", "settings.ai.ollamaServerUrl": "Ollama szerver URL-je", "settings.ai.ollamaTauriBypass": "Asztali felépítés: A WorldScript közvetlenül hívja az Ollamát – a böngésző CORS akadálya nélkül.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "A gyakori helyi portok vizsgálata", "settings.ai.scanNo": "nincs válasz", "settings.ai.scanOk": "elérhető", + "settings.ai.scanStateHttp": "HTTP-hiba", + "settings.ai.scanStateTimeout": "időtúllépés", + "settings.ai.scanUseUrl": "URL használata", "settings.ai.temperature.balanced": "1 – Kiegyensúlyozott", "settings.ai.temperature.creative": "2 – Kreatív", "settings.ai.temperature.precise": "0 – Pontos", diff --git a/public/locales/is/bundle.json b/public/locales/is/bundle.json index eb09a5b7..5598f2f9 100644 --- a/public/locales/is/bundle.json +++ b/public/locales/is/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AI sköpunarstig", "settings.ai.creativityDescription": "Hærri gildi gefa óvæntari niðurstöður.", "settings.ai.customModel": "Sérsniðin líkan", + "settings.ai.downloadDesktopCta": "Sækja skjáborðsforritið", "settings.ai.fallbackNone": "Engin", "settings.ai.fallbackStep1": "Fyrsta afturför", "settings.ai.fallbackStep2": "Önnur afturför", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ekki í boði", "settings.ai.localBackendPreset": "Forstilla staðbundin bakenda", "settings.ai.ollamaBrowserNote": "Ollama er aðeins fáanlegt í skjáborðsforritinu. Innihaldsöryggisstefna vafrans lokar á beinar tengingar við localhost.", - "settings.ai.ollamaHint": "Gakktu úr skugga um að ollama þjóna sé í gangi og CORS sé virkt.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama og staðværir OpenAI-samhæfðir þjónar (LM Studio, vLLM) eru aðeins í boði í skjáborðsforritinu. Vafrar loka beinum tengingum við localhost (Content Security Policy og Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Skjáborðsforrits er krafist fyrir staðværa þjóna", + "settings.ai.ollamaHint": "Gakktu úr skugga um að þjónninn sé í gangi (t.d. ollama serve). Skjáborðsforritið tengist beint — engin CORS-uppsetning nauðsynleg.", "settings.ai.ollamaModelHint": "Flýtivalsgerðir sem miðlarinn þinn hefur tilkynnt um – bankaðu til að nota.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Skrifborðsbygging: WorldScript hringir beint í Ollama - engin CORS hindrun vafra.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Skannaðu algengar staðbundnar hafnir", "settings.ai.scanNo": "ekkert svar", "settings.ai.scanOk": "náðist", + "settings.ai.scanStateHttp": "HTTP-villa", + "settings.ai.scanStateTimeout": "tímamörk liðin", + "settings.ai.scanUseUrl": "Nota þessa slóð", "settings.ai.temperature.balanced": "1 - Jafnvægi", "settings.ai.temperature.creative": "2 - Skapandi", "settings.ai.temperature.precise": "0 - Nákvæmt", diff --git a/public/locales/it/bundle.json b/public/locales/it/bundle.json index 927e7b8e..9c49a8fb 100644 --- a/public/locales/it/bundle.json +++ b/public/locales/it/bundle.json @@ -1621,6 +1621,7 @@ "settings.about.githubDescription": "Visualizza il codice sorgente, segnala problemi e contribuisci.", "settings.about.githubLabel": "Open-source su GitHub", "settings.about.liveDemo": "Prova la demo dal vivo", + "settings.about.productName": "WorldScript Studio", "settings.about.tauriVersion": "Versione runtime desktop", "settings.about.title": "Informazioni su WorldScript Studio", "settings.about.versionLabel": "Versione", @@ -1671,16 +1672,16 @@ "settings.advancedAi.model": "Modello IA", "settings.advancedAi.modelDescription": "Il modello IA usato per la generazione di scene, analisi e altre funzionalità IA. La disponibilità dipende dal provider selezionato.", "settings.advancedAi.modelRecommendationsIntro": "Checkpoint locali popolari (verifica i nomi nel tuo ambiente di esecuzione):", - "settings.advancedAi.ollamaPull.recommendedFor": "Consigliato per il tuo dispositivo:", + "settings.advancedAi.ollamaPull.batteryNote": "Ridotta la dimensione per risparmiare batteria.", + "settings.advancedAi.ollamaPull.installed": "Installato", "settings.advancedAi.ollamaPull.pull": "Scarica modello", "settings.advancedAi.ollamaPull.pulling": "Download del modello…", + "settings.advancedAi.ollamaPull.recommendedFor": "Consigliato per il tuo dispositivo:", "settings.advancedAi.ollamaPull.retry": "Riprova", - "settings.advancedAi.ollamaPull.installed": "Installato", - "settings.advancedAi.ollamaPull.useModel": "Usa questo modello", - "settings.advancedAi.ollamaPull.batteryNote": "Ridotta la dimensione per risparmiare batteria.", "settings.advancedAi.ollamaPull.tier.high-end": "Fascia alta", - "settings.advancedAi.ollamaPull.tier.mid-range": "Fascia media", "settings.advancedAi.ollamaPull.tier.low-end": "Fascia bassa", + "settings.advancedAi.ollamaPull.tier.mid-range": "Fascia media", + "settings.advancedAi.ollamaPull.useModel": "Usa questo modello", "settings.advancedAi.ragModeHint": "La modalità ibrida combina ricerca per parole chiave e comprensione semantica — ideale per la maggior parte delle storie. Ricostruisci l'indice dopo modifiche importanti.", "settings.advancedAi.ragModeHybrid": "Ibrido (semantico + lessicale, consigliato)", "settings.advancedAi.ragModeLabel": "Modalità di recupero del contesto", @@ -1729,6 +1730,7 @@ "settings.ai.creativity": "Livello di creatività dell'IA", "settings.ai.creativityDescription": "Valori più alti producono risultati più inaspettati.", "settings.ai.customModel": "Modello personalizzato", + "settings.ai.downloadDesktopCta": "Scarica l'app desktop", "settings.ai.fallbackNone": "Nessuno", "settings.ai.fallbackStep1": "Primo fallback", "settings.ai.fallbackStep2": "Secondo fallback", @@ -1812,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Non disponibile", "settings.ai.localBackendPreset": "Preset backend locale", "settings.ai.ollamaBrowserNote": "Ollama è disponibile solo nell'app desktop. La politica di sicurezza dei contenuti del browser blocca le connessioni dirette a localhost.", - "settings.ai.ollamaHint": "Assicurati che ollama serve sia in esecuzione e che CORS sia abilitato.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama e i server locali compatibili con OpenAI (LM Studio, vLLM) sono disponibili solo nell'app desktop. I browser bloccano le connessioni dirette a localhost (Content Security Policy e Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "App desktop richiesta per i server locali", + "settings.ai.ollamaHint": "Assicurati che il server sia in esecuzione (es. ollama serve). L'app desktop si connette direttamente — nessuna configurazione CORS necessaria.", "settings.ai.ollamaModelHint": "Selezione rapida dei modelli segnalati dal tuo server — tocca per usare.", "settings.ai.ollamaServerUrl": "URL del server Ollama", "settings.ai.ollamaTauriBypass": "Versione desktop: WorldScript chiama Ollama direttamente — nessuna barriera CORS del browser.", @@ -1844,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Scansiona porte locali comuni", "settings.ai.scanNo": "nessuna risposta", "settings.ai.scanOk": "raggiungibile", + "settings.ai.scanStateHttp": "errore HTTP", + "settings.ai.scanStateTimeout": "timeout", + "settings.ai.scanUseUrl": "Usa questo URL", "settings.ai.temperature.balanced": "1 – Equilibrato", "settings.ai.temperature.creative": "2 – Creativo", "settings.ai.temperature.precise": "0 – Preciso", @@ -2043,24 +2050,19 @@ "settings.editor.previewText2": "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.", "settings.editor.previewTitle": "Anteprima in tempo reale", "settings.editor.title": "Preferenze dell'editor", - "settings.featureFlags.description": "Prova funzionalità che stiamo ancora perfezionando. Il tuo feedback determina ciò che verrà pubblicato.", - "settings.featureFlags.category.core": "Scrittura", "settings.featureFlags.category.ai": "IA", - "settings.featureFlags.category.pipeline": "Flusso di modifica", - "settings.featureFlags.category.personalization": "Personalizzazione", "settings.featureFlags.category.analytics": "Analisi", - "settings.featureFlags.category.performance": "Prestazioni", - "settings.featureFlags.category.voice": "Voce", + "settings.featureFlags.category.core": "Scrittura", "settings.featureFlags.category.extensions": "Estensioni", - "settings.featureFlags.category.sync": "Sincronizzazione", "settings.featureFlags.category.i18n": "Lingua e layout", - "settings.featureFlags.dependency.requires": "Richiede {{name}}", + "settings.featureFlags.category.performance": "Prestazioni", + "settings.featureFlags.category.personalization": "Personalizzazione", + "settings.featureFlags.category.pipeline": "Flusso di modifica", + "settings.featureFlags.category.sync": "Sincronizzazione", + "settings.featureFlags.category.voice": "Voce", "settings.featureFlags.dependency.desktopOnly": "Solo app desktop", - "settings.featureFlags.risk.high": "Può usare molta memoria, GPU o budget di token.", - "settings.featureFlags.resetToDefaults": "Ripristina valori predefiniti", - "settings.featureFlags.resetTitle": "Ripristinare le funzionalità sperimentali?", - "settings.featureFlags.resetConfirm": "Questo ripristina tutte le funzionalità sperimentali al loro stato predefinito (attivo/disattivo). I tuoi progetti e contenuti non sono interessati.", - "settings.featureFlags.resetDone": "Funzionalità sperimentali ripristinate ai valori predefiniti.", + "settings.featureFlags.dependency.requires": "Richiede {{name}}", + "settings.featureFlags.description": "Prova funzionalità che stiamo ancora perfezionando. Il tuo feedback determina ciò che verrà pubblicato.", "settings.featureFlags.enableAdaptiveAiEngine": "Motore IA adattivo (selezione intelligente del backend)", "settings.featureFlags.enableAppHealthPanel": "Istantanea dello stato dell'app (informazioni)", "settings.featureFlags.enableBinderResearch": "Raccoglitore di ricerca (barra laterale del manoscritto)", @@ -2083,6 +2085,11 @@ "settings.featureFlags.enableVoiceSupport": "Comandi vocali e dettatura", "settings.featureFlags.enableVoiceWasm": "Motore vocale WASM (Whisper.cpp — offline)", "settings.featureFlags.enableWorkerBusV2": "WorkerBus v2 (orchestrazione tipizzata dei worker — Fase 2)", + "settings.featureFlags.resetConfirm": "Questo ripristina tutte le funzionalità sperimentali al loro stato predefinito (attivo/disattivo). I tuoi progetti e contenuti non sono interessati.", + "settings.featureFlags.resetDone": "Funzionalità sperimentali ripristinate ai valori predefiniti.", + "settings.featureFlags.resetTitle": "Ripristinare le funzionalità sperimentali?", + "settings.featureFlags.resetToDefaults": "Ripristina valori predefiniti", + "settings.featureFlags.risk.high": "Può usare molta memoria, GPU o budget di token.", "settings.featureFlags.title": "Funzionalità in accesso anticipato", "settings.font.custom": "Carattere personalizzato", "settings.font.mono": "Monospazio", @@ -2212,8 +2219,8 @@ "settings.openRouter.modelFetch.loading": "Caricamento del catalogo modelli…", "settings.openRouter.modelPlaceholder": "Seleziona o cerca un modello", "settings.openRouter.paidModelNote": "I modelli a pagamento richiedono crediti sul tuo account OpenRouter.", - "settings.openRouter.policyBlocked.mode": "OpenRouter non è disponibile in modalità IA Locale o Eco. Passa a Ibrida o Cloud in IA e Modelli per usarlo.", "settings.openRouter.policyBlocked.localOnly": "OpenRouter è bloccato perché “Solo archiviazione locale” è attivo. Disattivalo in Privacy e Dati per consentire l’IA nel cloud.", + "settings.openRouter.policyBlocked.mode": "OpenRouter non è disponibile in modalità IA Locale o Eco. Passa a Ibrida o Cloud in IA e Modelli per usarlo.", "settings.openRouter.preferredModel": "Modello preferito", "settings.openRouter.resetCircuit": "Reimposta", "settings.openRouter.resetCircuitAria": "Reimposta l'interruttore di OpenRouter", @@ -2345,8 +2352,8 @@ "settings.voice.enableHint": "Attiva comandi vocali, dettatura e feedback audio.", "settings.voice.enableLabel": "Abilita controllo vocale", "settings.voice.engine.auto": "Automatico (consigliato)", - "settings.voice.engine.wasm": "Modello WASM locale (offline)", "settings.voice.engine.privacyNote": "Privacy: «Web Speech API» invia l'audio al fornitore del browser (Google, Apple o Microsoft). «Modello WASM locale» funziona interamente sul dispositivo. «Auto» preferisce il locale e può ricorrere al cloud.", + "settings.voice.engine.wasm": "Modello WASM locale (offline)", "settings.voice.engine.webSpeech": "Web Speech API (cloud)", "settings.voice.feedbackLevel": "Livello di feedback audio", "settings.voice.intro": "Controlla WorldScript Studio con la voce. Scegli sotto un motore vocale cloud o completamente locale.", @@ -2389,7 +2396,6 @@ "voice.modelDownload.progress": "{{percent}}% completato", "voice.modelDownload.retry": "Riprova", "voice.modelDownload.title": "Download modello vocale", - "settings.about.productName": "WorldScript Studio", "sidebar.characterGraph": "Grafo dei personaggi", "sidebar.characterInterviews": "Interviste ai personaggi", "sidebar.characters": "Personaggi", diff --git a/public/locales/ja/bundle.json b/public/locales/ja/bundle.json index eb23181f..d4ec16c9 100644 --- a/public/locales/ja/bundle.json +++ b/public/locales/ja/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AIの創造性レベル", "settings.ai.creativityDescription": "値を大きくすると、より予期しない結果が生じます。", "settings.ai.customModel": "カスタムモデル", + "settings.ai.downloadDesktopCta": "デスクトップアプリをダウンロード", "settings.ai.fallbackNone": "なし", "settings.ai.fallbackStep1": "最初のフォールバック", "settings.ai.fallbackStep2": "2 番目のフォールバック", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "利用不可", "settings.ai.localBackendPreset": "ローカル バックエンド プリセット", "settings.ai.ollamaBrowserNote": "Ollama はデスクトップ アプリでのみ利用できます。ブラウザのコンテンツ セキュリティ ポリシーは、ローカルホストへの直接接続をブロックします。", - "settings.ai.ollamaHint": "ollamserve が実行中であり、CORS が有効になっていることを確認してください。", + "settings.ai.ollamaDesktopOnlyBody": "Ollama およびローカルの OpenAI 互換サーバー(LM Studio、vLLM)はデスクトップアプリでのみ利用できます。ブラウザーは localhost への直接接続をブロックします(Content Security Policy および Private Network Access)。", + "settings.ai.ollamaDesktopOnlyTitle": "ローカルサーバーにはデスクトップアプリが必要です", + "settings.ai.ollamaHint": "サーバーが起動していることを確認してください(例: ollama serve)。デスクトップアプリは直接接続するため、CORS の設定は不要です。", "settings.ai.ollamaModelHint": "サーバーから報告されたモデルをクイック選択します — タップして使用します。", "settings.ai.ollamaServerUrl": "オラマサーバーのURL", "settings.ai.ollamaTauriBypass": "デスクトップ ビルド: WorldScript は Ollama を直接呼び出します。ブラウザーの CORS バリアはありません。", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "共通のローカルポートをスキャンする", "settings.ai.scanNo": "応答なし", "settings.ai.scanOk": "到達可能な", + "settings.ai.scanStateHttp": "HTTP エラー", + "settings.ai.scanStateTimeout": "タイムアウト", + "settings.ai.scanUseUrl": "この URL を使用", "settings.ai.temperature.balanced": "1 – バランスのとれた", "settings.ai.temperature.creative": "2 – クリエイティブ", "settings.ai.temperature.precise": "0 – 正確", diff --git a/public/locales/ko/bundle.json b/public/locales/ko/bundle.json index 9a6cbe23..b760766f 100644 --- a/public/locales/ko/bundle.json +++ b/public/locales/ko/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AI 창의성 수준", "settings.ai.creativityDescription": "값이 높을수록 예상치 못한 결과가 더 많이 발생합니다.", "settings.ai.customModel": "맞춤형 모델", + "settings.ai.downloadDesktopCta": "데스크톱 앱 다운로드", "settings.ai.fallbackNone": "없음", "settings.ai.fallbackStep1": "첫 번째 대체", "settings.ai.fallbackStep2": "두 번째 대체", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "사용할 수 없음", "settings.ai.localBackendPreset": "로컬 백엔드 사전 설정", "settings.ai.ollamaBrowserNote": "Ollama는 데스크톱 앱에서만 사용할 수 있습니다. 브라우저의 콘텐츠 보안 정책은 localhost에 대한 직접 연결을 차단합니다.", - "settings.ai.ollamaHint": "ollama 서비스가 실행 중이고 CORS가 활성화되어 있는지 확인하세요.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama 및 로컬 OpenAI 호환 서버(LM Studio, vLLM)는 데스크톱 앱에서만 사용할 수 있습니다. 브라우저는 localhost에 대한 직접 연결을 차단합니다(Content Security Policy 및 Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "로컬 서버에는 데스크톱 앱이 필요합니다", + "settings.ai.ollamaHint": "서버가 실행 중인지 확인하세요(예: ollama serve). 데스크톱 앱은 직접 연결하므로 CORS 설정이 필요하지 않습니다.", "settings.ai.ollamaModelHint": "서버에서 보고한 모델을 빠르게 선택하세요. 탭하여 사용하세요.", "settings.ai.ollamaServerUrl": "올라마 서버 URL", "settings.ai.ollamaTauriBypass": "데스크탑 빌드: WorldScript는 브라우저 CORS 장벽 없이 Ollama를 직접 호출합니다.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "공통 로컬 포트 ​​스캔", "settings.ai.scanNo": "응답 없음", "settings.ai.scanOk": "도달 가능", + "settings.ai.scanStateHttp": "HTTP 오류", + "settings.ai.scanStateTimeout": "시간 초과", + "settings.ai.scanUseUrl": "이 URL 사용", "settings.ai.temperature.balanced": "1 - 균형 잡힌", "settings.ai.temperature.creative": "2 – 창의적", "settings.ai.temperature.precise": "0 – 정확함", diff --git a/public/locales/pt/bundle.json b/public/locales/pt/bundle.json index 67ef8cdc..4e03002b 100644 --- a/public/locales/pt/bundle.json +++ b/public/locales/pt/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "IA Creativity Level", "settings.ai.creativityDescription": "Valores mais altos produzem resultados mais inesperados.", "settings.ai.customModel": "Modelo personalizado", + "settings.ai.downloadDesktopCta": "Transferir a aplicação de desktop", "settings.ai.fallbackNone": "Nenhum", "settings.ai.fallbackStep1": "Primeiro substituto", "settings.ai.fallbackStep2": "Segundo substituto", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Indisponível", "settings.ai.localBackendPreset": "Predefinição de back-end local", "settings.ai.ollamaBrowserNote": "Ollama está disponível apenas no aplicativo de desktop. A Política de Segurança de Conteúdo do navegador bloqueia conexões diretas com o host local.", - "settings.ai.ollamaHint": "Certifique-se de que ollama serve esteja em execução e que o CORS esteja ativado.", + "settings.ai.ollamaDesktopOnlyBody": "O Ollama e os servidores locais compatíveis com OpenAI (LM Studio, vLLM) só estão disponíveis na aplicação de desktop. Os navegadores bloqueiam ligações diretas a localhost (Content Security Policy e Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Aplicação de desktop necessária para servidores locais", + "settings.ai.ollamaHint": "Certifique-se de que o servidor está em execução (p. ex. ollama serve). A aplicação de desktop liga-se diretamente — sem configuração CORS.", "settings.ai.ollamaModelHint": "Selecione rapidamente os modelos relatados pelo seu servidor – toque para usar.", "settings.ai.ollamaServerUrl": "URL do servidor Ollama", "settings.ai.ollamaTauriBypass": "Construção para desktop: WorldScript chama Ollama diretamente – sem barreira CORS do navegador.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Digitalize portas locais comuns", "settings.ai.scanNo": "sem resposta", "settings.ai.scanOk": "alcançável", + "settings.ai.scanStateHttp": "erro HTTP", + "settings.ai.scanStateTimeout": "tempo limite excedido", + "settings.ai.scanUseUrl": "Usar este URL", "settings.ai.temperature.balanced": "1 – Equilibrado", "settings.ai.temperature.creative": "2 – Criativo", "settings.ai.temperature.precise": "0 – Preciso", diff --git a/public/locales/ru/bundle.json b/public/locales/ru/bundle.json index ebb2fde6..201b046c 100644 --- a/public/locales/ru/bundle.json +++ b/public/locales/ru/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "Уровень творчества ИИ", "settings.ai.creativityDescription": "Более высокие значения дают более неожиданные результаты.", "settings.ai.customModel": "Пользовательская модель", + "settings.ai.downloadDesktopCta": "Скачать настольное приложение", "settings.ai.fallbackNone": "Никто", "settings.ai.fallbackStep1": "Первый запасной вариант", "settings.ai.fallbackStep2": "Второй запасной вариант", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Нет в наличии", "settings.ai.localBackendPreset": "Локальная настройка серверной части", "settings.ai.ollamaBrowserNote": "Оллама доступен только в настольном приложении. Политика безопасности контента браузера блокирует прямые подключения к локальному хосту.", - "settings.ai.ollamaHint": "Убедитесь, что служба ollama работает и CORS включен.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama и локальные OpenAI-совместимые серверы (LM Studio, vLLM) доступны только в настольном приложении. Браузеры блокируют прямые подключения к localhost (Content Security Policy и Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Для локальных серверов требуется настольное приложение", + "settings.ai.ollamaHint": "Убедитесь, что сервер запущен (например, ollama serve). Настольное приложение подключается напрямую — настройка CORS не требуется.", "settings.ai.ollamaModelHint": "Быстрый выбор моделей, о которых сообщает ваш сервер. Нажмите, чтобы использовать.", "settings.ai.ollamaServerUrl": "URL-адрес сервера Оллама", "settings.ai.ollamaTauriBypass": "Сборка для настольных компьютеров: WorldScript напрямую вызывает Ollama — без барьера CORS браузера.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Сканировать общие локальные порты", "settings.ai.scanNo": "нет ответа", "settings.ai.scanOk": "достижимый", + "settings.ai.scanStateHttp": "ошибка HTTP", + "settings.ai.scanStateTimeout": "тайм-аут", + "settings.ai.scanUseUrl": "Использовать этот URL", "settings.ai.temperature.balanced": "1 – Сбалансированный", "settings.ai.temperature.creative": "2 – Креатив", "settings.ai.temperature.precise": "0 – Точный", diff --git a/public/locales/sv/bundle.json b/public/locales/sv/bundle.json index cbf7c40e..d1066093 100644 --- a/public/locales/sv/bundle.json +++ b/public/locales/sv/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "AI-kreativitetsnivå", "settings.ai.creativityDescription": "Högre värden ger mer oväntade resultat.", "settings.ai.customModel": "Anpassad modell", + "settings.ai.downloadDesktopCta": "Ladda ner skrivbordsappen", "settings.ai.fallbackNone": "Ingen", "settings.ai.fallbackStep1": "Första fallback", "settings.ai.fallbackStep2": "Andra fallback", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "Ej tillgängligt", "settings.ai.localBackendPreset": "Lokal förinställning av backend", "settings.ai.ollamaBrowserNote": "Ollama är endast tillgänglig i skrivbordsappen. Webbläsarens innehållssäkerhetspolicy blockerar direktanslutningar till localhost.", - "settings.ai.ollamaHint": "Se till att ollamaserven körs och att CORS är aktiverat.", + "settings.ai.ollamaDesktopOnlyBody": "Ollama och lokala OpenAI-kompatibla servrar (LM Studio, vLLM) är endast tillgängliga i skrivbordsappen. Webbläsare blockerar direkta anslutningar till localhost (Content Security Policy och Private Network Access).", + "settings.ai.ollamaDesktopOnlyTitle": "Skrivbordsappen krävs för lokala servrar", + "settings.ai.ollamaHint": "Se till att servern körs (t.ex. ollama serve). Skrivbordsappen ansluter direkt — ingen CORS-konfiguration behövs.", "settings.ai.ollamaModelHint": "Snabbvalsmodeller rapporterade av din server – tryck för att använda.", "settings.ai.ollamaServerUrl": "Ollama Server URL", "settings.ai.ollamaTauriBypass": "Skrivbordsbygge: WorldScript anropar Ollama direkt — ingen CORS-barriär för webbläsaren.", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "Skanna vanliga lokala portar", "settings.ai.scanNo": "inget svar", "settings.ai.scanOk": "nås", + "settings.ai.scanStateHttp": "HTTP-fel", + "settings.ai.scanStateTimeout": "tidsgräns överskriden", + "settings.ai.scanUseUrl": "Använd den här URL:en", "settings.ai.temperature.balanced": "1 – Balanserad", "settings.ai.temperature.creative": "2 – Kreativt", "settings.ai.temperature.precise": "0 – Exakt", diff --git a/public/locales/zh/bundle.json b/public/locales/zh/bundle.json index cc94fc6e..71eb47f2 100644 --- a/public/locales/zh/bundle.json +++ b/public/locales/zh/bundle.json @@ -1730,6 +1730,7 @@ "settings.ai.creativity": "人工智能创造力水平", "settings.ai.creativityDescription": "较高的值会产生更多意想不到的结果。", "settings.ai.customModel": "定制型号", + "settings.ai.downloadDesktopCta": "下载桌面应用", "settings.ai.fallbackNone": "没有任何", "settings.ai.fallbackStep1": "第一个后备", "settings.ai.fallbackStep2": "第二次后备", @@ -1813,7 +1814,9 @@ "settings.ai.localAi.webgpuUnavailable": "不可用", "settings.ai.localBackendPreset": "本地后端预设", "settings.ai.ollamaBrowserNote": "Ollama 仅在桌面应用程序中可用。浏览器的内容安全策略阻止与本地主机的直接连接。", - "settings.ai.ollamaHint": "确保 ollama 服务正在运行并且 CORS 已启用。", + "settings.ai.ollamaDesktopOnlyBody": "Ollama 和本地 OpenAI 兼容服务器(LM Studio、vLLM)仅在桌面应用中可用。浏览器会阻止与 localhost 的直接连接(内容安全策略和专用网络访问)。", + "settings.ai.ollamaDesktopOnlyTitle": "本地服务器需要桌面应用", + "settings.ai.ollamaHint": "请确保服务器正在运行(例如 ollama serve)。桌面应用直接连接,无需配置 CORS。", "settings.ai.ollamaModelHint": "快速选择服务器报告的模型 - 点击即可使用。", "settings.ai.ollamaServerUrl": "奥拉马服务器 URL", "settings.ai.ollamaTauriBypass": "桌面构建:WorldScript 直接调用 Ollama — 无浏览器 CORS 障碍。", @@ -1845,6 +1848,9 @@ "settings.ai.scanLocalPorts": "扫描本地常用端口", "settings.ai.scanNo": "没有回应", "settings.ai.scanOk": "可达的", + "settings.ai.scanStateHttp": "HTTP 错误", + "settings.ai.scanStateTimeout": "超时", + "settings.ai.scanUseUrl": "使用此 URL", "settings.ai.temperature.balanced": "1 – 平衡", "settings.ai.temperature.creative": "2 – 创意", "settings.ai.temperature.precise": "0 – 精确", From 14d036723d798a22b26783c94f8bf371b2e4152b Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:48:01 +0200 Subject: [PATCH 05/14] chore(collab): vendor-fork audit, bump 10.3.0-sc2, drop dead y-webrtc dep (#60) Full-file diff of packages/collab-transport against upstream y-webrtc 10.3.0: no deviations beyond the three documented SC patches (PBKDF2 600k, extractable:false, return-before-reject) + DataChannel E2E encryption. Recorded in packages/collab-transport/AUDIT.md; fork bumped to -sc2. Cleanup: removed the deprecated patches/y-webrtc@10.3.0.patch and the dead root y-webrtc dependency (zero imports). Created the previously-referenced- but-missing scripts/verify-vendor-fork.mjs invariant guard and wired it into package.json (verify:vendor) + the CI security job. --- .github/workflows/ci.yml | 5 + VENDOR-FORKS.md | 19 +- package.json | 4 +- packages/collab-transport/AUDIT.md | 56 + packages/collab-transport/package.json | 2 +- packages/collab-transport/src/crypto.js | 6 +- patches/y-webrtc@10.3.0.patch | 76 - pnpm-lock.yaml | 1798 +++++++++++++---------- scripts/verify-vendor-fork.mjs | 61 + 9 files changed, 1136 insertions(+), 891 deletions(-) create mode 100644 packages/collab-transport/AUDIT.md delete mode 100644 patches/y-webrtc@10.3.0.patch create mode 100644 scripts/verify-vendor-fork.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b947d85..5e2af625 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,11 @@ jobs: - name: pnpm audit (high + critical) run: pnpm audit --audit-level=high + # QNBS-v3 (#60): vendored y-webrtc fork invariant guard (PBKDF2 600k, non-extractable keys, + # DataChannel encryption, no dangling upstream dep) — fails the build on fork drift. + - name: Vendor fork invariant guard + run: pnpm run verify:vendor + # QNBS-v3: osv-scanner.toml (in src-tauri/) suppresses accepted RUSTSEC advisories for Cargo.lock; # scan both lockfiles so npm + Rust advisories are caught on every push - name: OSV vulnerability scan diff --git a/VENDOR-FORKS.md b/VENDOR-FORKS.md index 2fd09f22..4108408b 100644 --- a/VENDOR-FORKS.md +++ b/VENDOR-FORKS.md @@ -8,19 +8,24 @@ upstream monitoring and patch porting. | Attribute | Value | |-----------|-------| | **Upstream** | `y-webrtc@10.3.0` | -| **Fork version** | `10.3.0-sc1` | +| **Fork version** | `10.3.0-sc2` | | **Reason for fork** | E2E encryption (AES-256-GCM via Web Crypto) is not available upstream. The fork adds PBKDF2 key derivation, non-extractable CryptoKeys, and encrypted WebRTC DataChannels compatible with the y-webrtc signalling protocol. | | **Critical invariants** | 1. PBKDF2 iterations must remain **600,000** (OWASP 2024 SHA-256 minimum).
    2. All derived `CryptoKey` instances must have `extractable: false`.
    3. `promise.reject()` in `decrypt()` must be prefixed with `return`. | -| **Update protocol** | 1. Watch upstream releases via GitHub API or Renovate (excluded in config).
    2. On new upstream release, create a diff branch `vendor/y-webrtc-`.
    3. Port the three encryption patches manually; run `packages/collab-transport` test suite.
    4. Update `VENDOR-DIFF.md` baseline and bump the `-scN` suffix. | +| **Update protocol** | 1. Watch upstream releases via GitHub API or Renovate (excluded in config).
    2. On new upstream release, create a diff branch `vendor/y-webrtc-`.
    3. Port the three encryption patches manually; run `packages/collab-transport` test suite.
    4. Update `packages/collab-transport/AUDIT.md` and bump the `-scN` suffix. | | **Owner** | qnbs | | **Issue tracker** | #60 | +## Audit log + +| Date | Auditor | Result | +|------|---------|--------| +| 2026-07-25 | Kimi Code | Full-file diff vs upstream `10.3.0`: no deviations beyond the three SC patches. Deprecated `patches/y-webrtc@10.3.0.patch` + dead root dependency removed; `verify-vendor-fork.mjs` created and wired into CI (`verify:vendor`); fork bumped to `10.3.0-sc2`. Details: `packages/collab-transport/AUDIT.md`. | + ## `patches/y-webrtc@10.3.0.patch` | Attribute | Value | |-----------|-------| -| **Status** | **DEPRECATED** — the vendor fork above supersedes this patch. | -| **Action** | Safe to remove once the fork is confirmed stable in production (v1.19.0+). | +| **Status** | **REMOVED** (2026-07-25, #60 audit) — the vendor fork above superseded this patch in v1.19.0. | ## Audit automation @@ -28,9 +33,11 @@ upstream monitoring and patch porting. - Asserts PBKDF2 iterations == 600k - Asserts `extractable: false` - Asserts `return promise.reject(...)` -- Asserts version string matches expected `-scN` suffix +- Asserts DataChannel encrypt/decrypt wiring, `-scN` version suffix, and no dangling upstream dep/patch -Wired into CI security job as `verify:vendor`. +Wired into the CI security job as `verify:vendor` (created 2026-07-25 during the #60 audit). +The per-release diff record lives in `packages/collab-transport/AUDIT.md` (replaces the formerly +planned `VENDOR-DIFF.md`). ## CVE / advisory monitoring (audit finding F-7) diff --git a/package.json b/package.json index 4706ecc6..95c4d305 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "tauri" ], "type": "module", - "packageManager": "pnpm@11.5.2", + "packageManager": "pnpm@11.17.0", "engines": { "node": ">=22.0.0", "pnpm": ">=11.0.0" @@ -28,6 +28,7 @@ "i18n:bundle": "node scripts/build-i18n.mjs", "i18n:check": "node scripts/check-i18n-keys.mjs && node scripts/build-i18n.mjs && node scripts/content-guard.mjs", "i18n:report": "node scripts/i18n-quality-report.mjs", + "verify:vendor": "node scripts/verify-vendor-fork.mjs", "i18n:status": "tsx scripts/i18n-status-dashboard.ts", "content:guard": "node scripts/content-guard.mjs", "parity:check": "tsx scripts/audit-feature-parity.ts", @@ -141,7 +142,6 @@ "uuid": "14", "xstate": "^5.32.1", "y-indexeddb": "^9.0.12", - "y-webrtc": "^10.3.0", "yjs": "^13.6.31", "zod": "^4.1.5", "zustand": "^5.0.14" diff --git a/packages/collab-transport/AUDIT.md b/packages/collab-transport/AUDIT.md new file mode 100644 index 00000000..89cb6c19 --- /dev/null +++ b/packages/collab-transport/AUDIT.md @@ -0,0 +1,56 @@ +# Vendor-Fork Audit — `@domain/collab-transport` (y-webrtc) + +- **Audit date:** 2026-07-25 · **Auditor:** Kimi Code · **Tracker:** issue #60 +- **Baseline:** npm tarball `y-webrtc@10.3.0` (`npm pack y-webrtc@10.3.0`, sha-pinned registry) +- **Fork state at audit:** `10.3.0-sc1` → bumped to **`10.3.0-sc2`** (audit marker, no behavioural change) + +## Method + +Full-file `diff -u` of upstream `src/crypto.js` and `src/y-webrtc.js` against the vendored copies. +Upstream 10.3.0 ships exactly these two source files; the fork adds `index.ts` + `*.d.ts` +(TypeScript shims — fork-only additions, no upstream counterpart to diff). + +## Result: fork matches upstream except for the three documented SC patches + +### `src/crypto.js` (3 intentional deviations) + +| # | Location | Deviation | Status | +|---|----------|-----------|--------| +| 1 | Fork header comment (lines 1–16) | Documents upstream tag, patch list, maintenance protocol, issue #60 link | ✅ expected | +| 2 | `deriveKey` | PBKDF2 iterations `100000` → **`600000`** (OWASP 2024 SHA-256 minimum) | ✅ invariant holds | +| 3 | `deriveKey` | `extractable` `true` → **`false`** (no `subtle.exportKey` leak) | ✅ invariant holds | +| 4 | `decrypt` error branch | added **`return`** before `promise.reject(...)` (silent-swallow fix) | ✅ invariant holds | + +### `src/y-webrtc.js` (1 intentional deviation, 3 call sites) + +RTCDataChannel payloads are now E2E-encrypted when `room.key` is set (upstream encrypts only +signaling-layer messages): + +| Site | Change | Status | +|------|--------|--------| +| `sendWebrtcConn` | `cryptoutils.encrypt(data, room.key)` before `peer.send`; plaintext fallback when no key | ✅ expected | +| `broadcastWebrtcConn` | same encryption wrap for room broadcasts | ✅ expected | +| `WebrtcConn` `peer.on('data')` | `cryptoutils.decrypt(data, room.key)` before `readPeerMessage`; plaintext fallback | ✅ expected | + +No other hunks. No upstream logic removed, no unexpected additions. `import * as cryptoutils from +'./crypto.js'` is present and used at the three sites (+ BroadcastChannel path, as upstream). + +## Housekeeping findings (fixed in this audit) + +| Finding | Resolution | +|---------|-----------| +| `patches/y-webrtc@10.3.0.patch` still present though deprecated since v1.19.0 | **removed** | +| Root `package.json` listed dead dependency `y-webrtc@^10.3.0` (zero imports) | **removed** + lockfile refreshed | +| `VENDOR-FORKS.md` referenced `scripts/verify-vendor-fork.mjs` + `verify:vendor` — neither existed | **created**, wired into package.json + CI `security` job | +| `VENDOR-DIFF.md` referenced by maintenance protocol — never existed | superseded by **this file** (`AUDIT.md`); protocol updated | + +## Invariant guard + +`pnpm run verify:vendor` (`scripts/verify-vendor-fork.mjs`) asserts: PBKDF2 600k iterations, +`extractable: false`, `return promise.reject(`, DataChannel encrypt/decrypt presence, `-scN` +version suffix, and absence of the dead upstream dependency/patch. Runs in the CI `security` job. + +## Next audit trigger + +Any upstream release `> 10.3.0`: diff `crypto.js` + `y-webrtc.js` against the new tag, port +security fixes, re-apply SC patches 1–3, bump `-scN`, record here and in `VENDOR-FORKS.md`. diff --git a/packages/collab-transport/package.json b/packages/collab-transport/package.json index e511608a..4392ce69 100644 --- a/packages/collab-transport/package.json +++ b/packages/collab-transport/package.json @@ -1,6 +1,6 @@ { "name": "@domain/collab-transport", - "version": "10.3.0-sc1", + "version": "10.3.0-sc2", "private": true, "type": "module", "description": "Vendored y-webrtc with WorldScript RTCDataChannel E2E encryption patch", diff --git a/packages/collab-transport/src/crypto.js b/packages/collab-transport/src/crypto.js index 71a91f53..cb0cb577 100644 --- a/packages/collab-transport/src/crypto.js +++ b/packages/collab-transport/src/crypto.js @@ -1,12 +1,16 @@ /** * VENDORED FORK — y-webrtc 10.3.0 * Upstream: https://github.com/yjs/y-webrtc | npm tag: v10.3.0 - * Package: @domain/collab-transport v10.3.0-sc1 (vendored 2026-05-28) + * Package: @domain/collab-transport v10.3.0-sc2 (vendored 2026-05-28, audited 2026-07-25) * * WorldScript patches (C-1, 2026-05-28 — commit 63afa69): * 1. PBKDF2 iterations raised 100k → 310k → 600k (OWASP 2024 SHA-256 minimum) * 2. deriveKey: extractable=false (prevents key export via subtle.exportKey) * 3. encryptMessageContent: added `return` before promise.reject() (was silent swallow) + * (y-webrtc.js: RTCDataChannel payloads encrypted/decrypted via cryptoutils when room.key set) + * + * 2026-07-25 audit (#60): full-file diff vs upstream 10.3.0 — no deviations beyond the patches + * above. See AUDIT.md. Invariant guard: `pnpm run verify:vendor`. * * SECURITY MAINTENANCE — Renovate cannot auto-update this fork. * On any new y-webrtc release: diff crypto.js + y-webrtc.js against the new tag, diff --git a/patches/y-webrtc@10.3.0.patch b/patches/y-webrtc@10.3.0.patch deleted file mode 100644 index 39a65bd7..00000000 --- a/patches/y-webrtc@10.3.0.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff --git a/src/y-webrtc.js b/src/y-webrtc.js -index 609328a25583f5000571bdec8b3e5ff53b322315..360dc3203175b894942a9e0925c3cdcdf6107e45 100644 ---- a/src/y-webrtc.js -+++ b/src/y-webrtc.js -@@ -145,9 +145,19 @@ const readPeerMessage = (peerConn, buf) => { - */ - const sendWebrtcConn = (webrtcConn, encoder) => { - log('send message to ', logging.BOLD, webrtcConn.remotePeerId, logging.UNBOLD, logging.GREY, ' (', webrtcConn.room.name, ')', logging.UNCOLOR) -- try { -- webrtcConn.peer.send(encoding.toUint8Array(encoder)) -- } catch (e) {} -+ const room = webrtcConn.room -+ const data = encoding.toUint8Array(encoder) -+ if (room.key) { -+ cryptoutils.encrypt(data, room.key).then(encrypted => { -+ try { -+ webrtcConn.peer.send(encrypted) -+ } catch (e) {} -+ }).catch(() => {}) -+ } else { -+ try { -+ webrtcConn.peer.send(data) -+ } catch (e) {} -+ } - } - - /** -@@ -156,11 +166,21 @@ const sendWebrtcConn = (webrtcConn, encoder) => { - */ - const broadcastWebrtcConn = (room, m) => { - log('broadcast message in ', logging.BOLD, room.name, logging.UNBOLD) -- room.webrtcConns.forEach(conn => { -- try { -- conn.peer.send(m) -- } catch (e) {} -- }) -+ if (room.key) { -+ cryptoutils.encrypt(m, room.key).then(encrypted => { -+ room.webrtcConns.forEach(conn => { -+ try { -+ conn.peer.send(encrypted) -+ } catch (e) {} -+ }) -+ }).catch(() => {}) -+ } else { -+ room.webrtcConns.forEach(conn => { -+ try { -+ conn.peer.send(m) -+ } catch (e) {} -+ }) -+ } - } - - export class WebrtcConn { -@@ -230,9 +250,18 @@ export class WebrtcConn { - announceSignalingInfo(room) - }) - this.peer.on('data', data => { -- const answer = readPeerMessage(this, data) -- if (answer !== null) { -- sendWebrtcConn(this, answer) -+ if (room.key) { -+ cryptoutils.decrypt(data, room.key).then(plaintext => { -+ const answer = readPeerMessage(this, plaintext) -+ if (answer !== null) { -+ sendWebrtcConn(this, answer) -+ } -+ }).catch(() => {}) -+ } else { -+ const answer = readPeerMessage(this, data) -+ if (answer !== null) { -+ sendWebrtcConn(this, answer) -+ } - } - }) - } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40bb9139..db930aef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,7 +89,7 @@ importers: version: 5.2.8 '@google/genai': specifier: ^2.8.0 - version: 2.8.0 + version: 2.8.0(supports-color@10.2.2) '@reduxjs/toolkit': specifier: ^2.12.0 version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) @@ -174,9 +174,6 @@ importers: y-indexeddb: specifier: ^9.0.12 version: 9.0.12(yjs@13.6.31) - y-webrtc: - specifier: ^10.3.0 - version: 10.3.0(yjs@13.6.31) yjs: specifier: ^13.6.31 version: 13.6.31 @@ -195,7 +192,7 @@ importers: version: 2.4.16 '@lhci/cli': specifier: ^0.15.1 - version: 0.15.1 + version: 0.15.1(supports-color@10.2.2) '@playwright/test': specifier: ^1.61.0 version: 1.61.0 @@ -204,25 +201,25 @@ importers: version: 10.4.5(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@storybook/builder-vite': specifier: ^10.4.5 - version: 10.4.5(esbuild@0.28.1)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) '@storybook/react': specifier: ^10.4.5 - version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3) + version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3) '@storybook/react-vite': specifier: ^10.4.5 - version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) '@storybook/test-runner': specifier: ^0.24.4 - version: 0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + version: 0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(debug@4.4.3(supports-color@10.2.2))(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2) '@stryker-mutator/core': specifier: ^9.2.0 - version: 9.6.1(@types/node@25.9.2) + version: 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) '@stryker-mutator/typescript-checker': specifier: ^9.6.1 - version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(typescript@6.0.3) + version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(typescript@6.0.3) '@stryker-mutator/vitest-runner': specifier: ^9.2.0 - version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(vitest@4.1.9) + version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(vitest@4.1.9) '@tailwindcss/vite': specifier: ^4.3.0 version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -267,7 +264,7 @@ importers: version: 6.2.5 http-server: specifier: ^14.1.1 - version: 14.1.1 + version: 14.1.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) jsdom: specifier: ^29.1.1 version: 29.1.1 @@ -276,7 +273,7 @@ importers: version: 17.0.7 rollup-plugin-visualizer: specifier: ^7.0.1 - version: 7.0.1(rolldown@1.0.3)(rollup@2.80.0) + version: 7.0.1(rolldown@1.0.3)(rollup@4.62.2) simple-git-hooks: specifier: ^2.13.1 version: 2.13.1 @@ -297,13 +294,13 @@ importers: version: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) vite-plugin-pwa: specifier: ^1.3.0 - version: 1.3.0(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) + version: 1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2))(workbox-window@7.4.1) vitest: specifier: ^4.1.9 version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) wait-on: specifier: ^9.0.10 - version: 9.0.10 + version: 9.0.10(debug@4.4.3(supports-color@10.2.2)) wrangler: specifier: ^4.99.0 version: 4.99.0 @@ -330,7 +327,7 @@ importers: version: 0.2.117 simple-peer: specifier: ^9.11.0 - version: 9.11.1 + version: 9.11.1(supports-color@10.2.2) y-protocols: specifier: ^1.0.6 version: 1.0.7(yjs@13.6.31) @@ -1987,12 +1984,6 @@ packages: '@mlc-ai/web-llm@0.2.84': resolution: {integrity: sha512-hrOWzK4/nGNmgoRKT8pgVmZZ2oEPpbblIWQOwpqNyvK2dysHw3KVB1gNJOuRcQfKOPhucEhX1NJzXzgMDnwSCQ==} - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.1.5': resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: @@ -2378,19 +2369,21 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/plugin-babel@5.3.1': - resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} - engines: {node: '>= 10.0.0'} + '@rollup/plugin-babel@6.1.0': + resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} + engines: {node: '>=14.0.0'} peerDependencies: '@babel/core': '>=7.29.6' '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: '@types/babel__core': optional: true + rollup: + optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -2398,25 +2391,23 @@ packages: rollup: optional: true - '@rollup/plugin-replace@2.4.2': - resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - '@rollup/pluginutils@3.1.0': - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0 + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true '@rollup/pluginutils@5.4.0': resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} @@ -2427,6 +2418,144 @@ packages: rollup: optional: true + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} + cpu: [x64] + os: [win32] + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -2594,9 +2723,6 @@ packages: '@stryker-mutator/core': 9.6.1 vitest: '>=2.0.0' - '@surma/rollup-plugin-off-main-thread@2.2.3': - resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} - '@swc/core-darwin-arm64@1.15.33': resolution: {integrity: sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA==} engines: {node: '>=10'} @@ -2931,6 +3057,10 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==} + engines: {node: '>=12'} + '@turbo/darwin-64@2.9.18': resolution: {integrity: sha512-9f27peFu16ur8c0v9nUFUEyBnbKuuFsUTjHFWfmwGfzySBXbHwzU44QhZon6Mznz0cHsIr3984NQj/bVrnGSRw==} cpu: [x64] @@ -3024,9 +3154,6 @@ packages: '@types/doctrine@0.0.9': resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} - '@types/estree@0.0.39': - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -4368,9 +4495,6 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -4381,6 +4505,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eta@4.6.0: + resolution: {integrity: sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==} + engines: {node: '>=20'} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -5608,9 +5736,6 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -6406,9 +6531,9 @@ packages: rollup: optional: true - rollup@2.80.0: - resolution: {integrity: sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==} - engines: {node: '>=10.0.0'} + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-applescript@7.1.0: @@ -6626,10 +6751,6 @@ packages: engines: {node: '>= 8'} deprecated: The work that was done in this beta branch won't be included in future versions - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - spawn-wrap@2.0.0: resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} engines: {node: '>=8'} @@ -7372,54 +7493,54 @@ packages: resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} engines: {node: '>=12.17'} - workbox-background-sync@7.4.0: - resolution: {integrity: sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==} + workbox-background-sync@7.4.1: + resolution: {integrity: sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==} - workbox-broadcast-update@7.4.0: - resolution: {integrity: sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==} + workbox-broadcast-update@7.4.1: + resolution: {integrity: sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==} - workbox-build@7.4.0: - resolution: {integrity: sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==} + workbox-build@7.4.1: + resolution: {integrity: sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==} engines: {node: '>=20.0.0'} - workbox-cacheable-response@7.4.0: - resolution: {integrity: sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==} + workbox-cacheable-response@7.4.1: + resolution: {integrity: sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==} - workbox-core@7.4.0: - resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==} + workbox-core@7.4.1: + resolution: {integrity: sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==} - workbox-expiration@7.4.0: - resolution: {integrity: sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==} + workbox-expiration@7.4.1: + resolution: {integrity: sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==} - workbox-google-analytics@7.4.0: - resolution: {integrity: sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==} + workbox-google-analytics@7.4.1: + resolution: {integrity: sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==} - workbox-navigation-preload@7.4.0: - resolution: {integrity: sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==} + workbox-navigation-preload@7.4.1: + resolution: {integrity: sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==} - workbox-precaching@7.4.0: - resolution: {integrity: sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==} + workbox-precaching@7.4.1: + resolution: {integrity: sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==} - workbox-range-requests@7.4.0: - resolution: {integrity: sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==} + workbox-range-requests@7.4.1: + resolution: {integrity: sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==} - workbox-recipes@7.4.0: - resolution: {integrity: sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==} + workbox-recipes@7.4.1: + resolution: {integrity: sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==} - workbox-routing@7.4.0: - resolution: {integrity: sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==} + workbox-routing@7.4.1: + resolution: {integrity: sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==} - workbox-strategies@7.4.0: - resolution: {integrity: sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==} + workbox-strategies@7.4.1: + resolution: {integrity: sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==} - workbox-streams@7.4.0: - resolution: {integrity: sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==} + workbox-streams@7.4.1: + resolution: {integrity: sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==} - workbox-sw@7.4.0: - resolution: {integrity: sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==} + workbox-sw@7.4.1: + resolution: {integrity: sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==} - workbox-window@7.4.0: - resolution: {integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==} + workbox-window@7.4.1: + resolution: {integrity: sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==} workerd@1.20260609.1: resolution: {integrity: sha512-KF/Y/8f4VoXCk87NuU6RqmO0X5fdzcrxU3XzAgoPUpnH9t1ZyzRgX1O/9sJvjItxroCBTEBzKssda02Dz9i6BA==} @@ -7523,13 +7644,6 @@ packages: peerDependencies: yjs: ^13.0.0 - y-webrtc@10.3.0: - resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} - engines: {node: '>=12'} - hasBin: true - peerDependencies: - yjs: ^13.6.8 - y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -7720,20 +7834,20 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -7772,45 +7886,45 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 resolve: 1.22.12 transitivePeerDependencies: @@ -7818,33 +7932,33 @@ snapshots: '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.28.5(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -7860,43 +7974,43 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-wrap-function': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-wrap-function': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.7)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.27.1(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -7913,10 +8027,10 @@ snapshots: '@babel/helper-validator-option@7.29.7': {} - '@babel/helper-wrap-function@7.29.7': + '@babel/helper-wrap-function@7.29.7(supports-color@10.2.2)': dependencies: '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -7934,628 +8048,628 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.7)': + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-globals': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 '@babel/template': 7.29.7 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.7)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/traverse': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.7)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/preset-env@7.29.7(@babel/core@7.29.7)': + '@babel/preset-env@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7) - '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7) - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) - babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2)) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) core-js-compat: 3.49.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 '@babel/types': 7.29.7 esutils: 2.0.3 - '@babel/preset-typescript@7.28.5(@babel/core@7.29.7)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.7) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -8575,7 +8689,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.7(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -8583,7 +8697,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -8870,9 +8984,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@google/genai@2.8.0': + '@google/genai@2.8.0(supports-color@10.2.2)': dependencies: - google-auth-library: 10.7.0 + google-auth-library: 10.7.0(supports-color@10.2.2) p-retry: 4.6.2 protobufjs: 8.6.1 ws: 8.21.0 @@ -9157,13 +9271,13 @@ snapshots: jest-util: 30.4.1 slash: 3.0.0 - '@jest/core@30.4.2': + '@jest/core@30.4.2(supports-color@10.2.2)': dependencies: '@jest/console': 30.4.1 '@jest/pattern': 30.4.0 - '@jest/reporters': 30.4.1 + '@jest/reporters': 30.4.1(supports-color@10.2.2) '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 '@types/node': 25.9.2 ansi-escapes: 4.3.2 @@ -9173,15 +9287,15 @@ snapshots: fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 jest-changed-files: 30.4.1 - jest-config: 30.4.2(@types/node@25.9.2) + jest-config: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) jest-haste-map: 30.4.1 jest-message-util: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-resolve-dependencies: 30.4.2 - jest-runner: 30.4.2 - jest-runtime: 30.4.2 - jest-snapshot: 30.4.1 + jest-resolve-dependencies: 30.4.2(supports-color@10.2.2) + jest-runner: 30.4.2(supports-color@10.2.2) + jest-runtime: 30.4.2(supports-color@10.2.2) + jest-snapshot: 30.4.1(supports-color@10.2.2) jest-util: 30.4.1 jest-validate: 30.4.1 jest-watcher: 30.4.1 @@ -9210,10 +9324,10 @@ snapshots: dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@30.4.1': + '@jest/expect@30.4.1(supports-color@10.2.2)': dependencies: expect: 30.4.1 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -9228,10 +9342,10 @@ snapshots: '@jest/get-type@30.1.0': {} - '@jest/globals@30.4.1': + '@jest/globals@30.4.1(supports-color@10.2.2)': dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1 + '@jest/expect': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 jest-mock: 30.4.1 transitivePeerDependencies: @@ -9242,12 +9356,12 @@ snapshots: '@types/node': 25.9.2 jest-regex-util: 30.4.0 - '@jest/reporters@30.4.1': + '@jest/reporters@30.4.1(supports-color@10.2.2)': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 '@types/node': 25.9.2 @@ -9257,9 +9371,9 @@ snapshots: glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3 + istanbul-lib-instrument: 6.0.3(supports-color@10.2.2) istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 + istanbul-lib-source-maps: 5.0.6(supports-color@10.2.2) istanbul-reports: 3.2.0 jest-message-util: 30.4.1 jest-util: 30.4.1 @@ -9301,12 +9415,12 @@ snapshots: jest-haste-map: 30.4.1 slash: 3.0.0 - '@jest/transform@30.4.1': + '@jest/transform@30.4.1(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 7.0.1 + babel-plugin-istanbul: 7.0.1(supports-color@10.2.2) chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 @@ -9367,19 +9481,19 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@lhci/cli@0.15.1': + '@lhci/cli@0.15.1(supports-color@10.2.2)': dependencies: - '@lhci/utils': 0.15.1 - chrome-launcher: 1.2.1 - compression: 1.8.1 - debug: 4.4.3 - express: 4.22.1 + '@lhci/utils': 0.15.1(supports-color@10.2.2) + chrome-launcher: 1.2.1(supports-color@10.2.2) + compression: 1.8.1(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + express: 4.22.1(supports-color@10.2.2) inquirer: 6.5.2 isomorphic-fetch: 3.0.0 - lighthouse: 12.6.1 - lighthouse-logger: 1.2.0 + lighthouse: 12.6.1(supports-color@10.2.2) + lighthouse-logger: 1.2.0(supports-color@10.2.2) open: 7.4.2 - proxy-agent: 6.5.0 + proxy-agent: 6.5.0(supports-color@10.2.2) tmp: 0.2.7 uuid: 14.0.0 yargs: 15.4.1 @@ -9393,12 +9507,12 @@ snapshots: - supports-color - utf-8-validate - '@lhci/utils@0.15.1': + '@lhci/utils@0.15.1(supports-color@10.2.2)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) isomorphic-fetch: 3.0.0 js-yaml: 4.2.0 - lighthouse: 12.6.1 + lighthouse: 12.6.1(supports-color@10.2.2) tree-kill: 1.2.2 transitivePeerDependencies: - bare-abort-controller @@ -9414,13 +9528,6 @@ snapshots: loglevel: 1.9.2 optional: true - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -9592,12 +9699,12 @@ snapshots: '@poppinss/exception@1.2.3': {} - '@puppeteer/browsers@2.13.0': + '@puppeteer/browsers@2.13.0(supports-color@10.2.2)': dependencies: - debug: 4.4.3 - extract-zip: 2.0.1 + debug: 4.4.3(supports-color@10.2.2) + extract-zip: 2.0.1(supports-color@10.2.2) progress: 2.0.3 - proxy-agent: 6.5.0 + proxy-agent: 6.5.0(supports-color@10.2.2) semver: 7.8.4 tar-fs: 3.1.2 yargs: 17.7.2 @@ -9659,7 +9766,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-win32-arm64-msvc@1.0.3': @@ -9670,55 +9777,124 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-babel@5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(@types/babel__core@7.20.5)(rollup@4.62.2)(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 - '@rollup/pluginutils': 3.1.0(rollup@2.80.0) - rollup: 2.80.0 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) optionalDependencies: '@types/babel__core': 7.20.5 + rollup: 4.62.2 transitivePeerDependencies: - supports-color - '@rollup/plugin-node-resolve@15.3.1(rollup@2.80.0)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@2.80.0) + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.12 optionalDependencies: - rollup: 2.80.0 + rollup: 4.62.2 - '@rollup/plugin-replace@2.4.2(rollup@2.80.0)': + '@rollup/plugin-replace@6.0.3(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.80.0) - magic-string: 0.25.9 - rollup: 2.80.0 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.62.2 - '@rollup/plugin-terser@0.4.4(rollup@2.80.0)': + '@rollup/plugin-terser@1.0.0(rollup@4.62.2)': dependencies: serialize-javascript: 7.0.5 smob: 1.6.2 terser: 5.48.0 optionalDependencies: - rollup: 2.80.0 - - '@rollup/pluginutils@3.1.0(rollup@2.80.0)': - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.2 - rollup: 2.80.0 + rollup: 4.62.2 - '@rollup/pluginutils@5.4.0(rollup@2.80.0)': + '@rollup/pluginutils@5.4.0(rollup@4.62.2)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 2.80.0 + rollup: 4.62.2 + + '@rollup/rollup-android-arm-eabi@4.62.2': + optional: true + + '@rollup/rollup-android-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-x64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.2': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.2': + optional: true '@sec-ant/readable-stream@0.4.1': {} @@ -9780,9 +9956,9 @@ snapshots: axe-core: 4.12.1 storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@storybook/builder-vite@10.4.5(esbuild@0.28.1)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + '@storybook/builder-vite@10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': dependencies: - '@storybook/csf-plugin': 10.4.5(esbuild@0.28.1)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + '@storybook/csf-plugin': 10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ts-dedent: 2.3.0 vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) @@ -9791,13 +9967,13 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.4.5(esbuild@0.28.1)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + '@storybook/csf-plugin@10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': dependencies: storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) unplugin: 2.3.11 optionalDependencies: esbuild: 0.28.1 - rollup: 2.80.0 + rollup: 4.62.2 vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) '@storybook/global@5.0.0': {} @@ -9816,16 +9992,16 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@storybook/react-vite@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + '@storybook/react-vite@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) - '@rollup/pluginutils': 5.4.0(rollup@2.80.0) - '@storybook/builder-vite': 10.4.5(esbuild@0.28.1)(rollup@2.80.0)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) - '@storybook/react': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3) + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) + '@storybook/builder-vite': 10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + '@storybook/react': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3) empathic: 2.0.1 magic-string: 0.30.21 react: 19.2.7 - react-docgen: 8.0.3 + react-docgen: 8.0.3(supports-color@10.2.2) react-dom: 19.2.7(react@19.2.7) resolve: 1.22.12 storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -9840,12 +10016,12 @@ snapshots: - typescript - webpack - '@storybook/react@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)': + '@storybook/react@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 '@storybook/react-dom-shim': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) react: 19.2.7 - react-docgen: 8.0.3 + react-docgen: 8.0.3(supports-color@10.2.2) react-docgen-typescript: 2.4.0(typescript@6.0.3) react-dom: 19.2.7(react@19.2.7) storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -9856,9 +10032,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/test-runner@0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@storybook/test-runner@0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(debug@4.4.3(supports-color@10.2.2))(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/generator': 7.29.1 '@babel/template': 7.28.6 '@babel/types': 7.29.0 @@ -9866,15 +10042,15 @@ snapshots: '@swc/core': 1.15.33(@swc/helpers@0.5.21) '@swc/jest': 0.2.39(@swc/core@1.15.33(@swc/helpers@0.5.21)) expect-playwright: 0.8.0 - jest: 30.4.2(@types/node@25.9.2) - jest-circus: 30.4.2 + jest: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) + jest-circus: 30.4.2(supports-color@10.2.2) jest-environment-node: 30.4.1 jest-junit: 16.0.0 - jest-process-manager: 0.4.0 - jest-runner: 30.4.2 + jest-process-manager: 0.4.0(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) + jest-runner: 30.4.2(supports-color@10.2.2) jest-serializer-html: 7.1.0 - jest-watch-typeahead: 3.0.1(jest@30.4.2(@types/node@25.9.2)) - nyc: 15.1.0 + jest-watch-typeahead: 3.0.1(jest@30.4.2(@types/node@25.9.2)(supports-color@10.2.2)) + nyc: 15.1.0(supports-color@10.2.2) playwright: 1.61.0 playwright-core: 1.61.0 rimraf: 3.0.2 @@ -9897,11 +10073,11 @@ snapshots: tslib: 2.8.1 typed-inject: 5.0.0 - '@stryker-mutator/core@9.6.1(@types/node@25.9.2)': + '@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2)': dependencies: '@inquirer/prompts': 8.4.2(@types/node@25.9.2) '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/instrumenter': 9.6.1 + '@stryker-mutator/instrumenter': 9.6.1(supports-color@10.2.2) '@stryker-mutator/util': 9.6.1 ajv: 8.18.0 chalk: 5.6.2 @@ -9929,14 +10105,14 @@ snapshots: - '@types/node' - supports-color - '@stryker-mutator/instrumenter@9.6.1': + '@stryker-mutator/instrumenter@9.6.1(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/generator': 7.29.1 '@babel/parser': 7.29.3 - '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.7) - '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.7) - '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@stryker-mutator/api': 9.6.1 '@stryker-mutator/util': 9.6.1 angular-html-parser: 10.4.0 @@ -9946,32 +10122,25 @@ snapshots: transitivePeerDependencies: - supports-color - '@stryker-mutator/typescript-checker@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(typescript@6.0.3)': + '@stryker-mutator/typescript-checker@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(typescript@6.0.3)': dependencies: '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/core': 9.6.1(@types/node@25.9.2) + '@stryker-mutator/core': 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) '@stryker-mutator/util': 9.6.1 semver: 7.7.4 typescript: 6.0.3 '@stryker-mutator/util@9.6.1': {} - '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(vitest@4.1.9)': + '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(vitest@4.1.9)': dependencies: '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/core': 9.6.1(@types/node@25.9.2) + '@stryker-mutator/core': 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) '@stryker-mutator/util': 9.6.1 semver: 7.7.4 tslib: 2.8.1 vitest: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) - '@surma/rollup-plugin-off-main-thread@2.2.3': - dependencies: - ejs: 3.1.10 - json5: 2.2.3 - magic-string: 0.25.9 - string.prototype.matchall: 4.0.12 - '@swc/core-darwin-arm64@1.15.33': optional: true @@ -10229,6 +10398,13 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.30.21 + string.prototype.matchall: 4.0.12 + '@turbo/darwin-64@2.9.18': optional: true @@ -10314,8 +10490,6 @@ snapshots: '@types/doctrine@0.0.9': {} - '@types/estree@0.0.39': {} - '@types/estree@1.0.9': {} '@types/istanbul-lib-coverage@2.0.6': {} @@ -10748,9 +10922,9 @@ snapshots: axe-core@4.12.1: {} - axios@1.16.0: + axios@1.16.0(debug@4.4.3(supports-color@10.2.2)): dependencies: - follow-redirects: 1.16.0 + follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2)) form-data: 4.0.6 proxy-from-env: 2.1.0 transitivePeerDependencies: @@ -10758,25 +10932,25 @@ snapshots: b4a@1.8.0: {} - babel-jest@30.4.1(@babel/core@7.29.7): + babel-jest@30.4.1(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 - '@jest/transform': 30.4.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@jest/transform': 30.4.1(supports-color@10.2.2) '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.4.0(@babel/core@7.29.7) + babel-plugin-istanbul: 7.0.1(supports-color@10.2.2) + babel-preset-jest: 30.4.0(@babel/core@7.29.7(supports-color@10.2.2)) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@7.0.1: + babel-plugin-istanbul@7.0.1(supports-color@10.2.2): dependencies: '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.6 - istanbul-lib-instrument: 6.0.3 + istanbul-lib-instrument: 6.0.3(supports-color@10.2.2) test-exclude: 6.0.0 transitivePeerDependencies: - supports-color @@ -10785,54 +10959,54 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) - - babel-preset-jest@30.4.0(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7(supports-color@10.2.2)): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) + + babel-preset-jest@30.4.0(@babel/core@7.29.7(supports-color@10.2.2)): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) babel-plugin-jest-hoist: 30.4.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@10.2.2)) balanced-match@4.0.4: {} @@ -10893,11 +11067,11 @@ snapshots: bluebird@3.4.7: {} - body-parser@1.20.4: + body-parser@1.20.4(supports-color@10.2.2): dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 destroy: 1.2.0 http-errors: 2.0.1 @@ -11029,12 +11203,12 @@ snapshots: check-error@2.1.3: {} - chrome-launcher@1.2.1: + chrome-launcher@1.2.1(supports-color@10.2.2): dependencies: '@types/node': 25.9.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 - lighthouse-logger: 2.0.2 + lighthouse-logger: 2.0.2(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -11137,11 +11311,11 @@ snapshots: dependencies: mime-db: 1.54.0 - compression@1.8.1: + compression@1.8.1(supports-color@10.2.2): dependencies: bytes: 3.1.2 compressible: 2.0.18 - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) negotiator: 0.6.4 on-headers: 1.1.0 safe-buffer: 5.2.1 @@ -11326,13 +11500,17 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - debug@2.6.9: + debug@2.6.9(supports-color@10.2.2): dependencies: ms: 2.0.0 + optionalDependencies: + supports-color: 10.2.2 - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decamelize@1.2.0: {} @@ -11657,8 +11835,6 @@ snapshots: estraverse@5.3.0: {} - estree-walker@1.0.1: {} - estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -11667,6 +11843,8 @@ snapshots: esutils@2.0.3: {} + eta@4.6.0: {} + etag@1.8.1: {} eventemitter3@4.0.7: {} @@ -11729,21 +11907,21 @@ snapshots: jest-mock: 30.4.1 jest-util: 30.4.1 - express@4.22.1: + express@4.22.1(supports-color@10.2.2): dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.4 + body-parser: 1.20.4(supports-color@10.2.2) content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.0.7 - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.2 + finalhandler: 1.3.2(supports-color@10.2.2) fresh: 0.5.2 http-errors: 2.0.1 merge-descriptors: 1.0.3 @@ -11755,8 +11933,8 @@ snapshots: qs: 6.15.2 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.2 - serve-static: 1.16.3 + send: 0.19.2(supports-color@10.2.2) + serve-static: 1.16.3(supports-color@10.2.2) setprototypeof: 1.2.0 statuses: 2.0.2 type-is: 1.6.18 @@ -11773,9 +11951,9 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.2.7 - extract-zip@2.0.1: + extract-zip@2.0.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -11842,9 +12020,9 @@ snapshots: dependencies: minimatch: 5.1.9 - finalhandler@1.3.2: + finalhandler@1.3.2(supports-color@10.2.2): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -11895,7 +12073,9 @@ snapshots: kapsule: 1.16.3 preact: 10.29.1 - follow-redirects@1.16.0: {} + follow-redirects@1.16.0(debug@4.4.3(supports-color@10.2.2)): + optionalDependencies: + debug: 4.4.3(supports-color@10.2.2) for-each@0.3.5: dependencies: @@ -11980,17 +12160,17 @@ snapshots: functions-have-names@1.2.3: {} - gaxios@7.1.5: + gaxios@7.1.5(supports-color@10.2.2): dependencies: extend: 3.0.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) node-fetch: 3.3.2 transitivePeerDependencies: - supports-color - gcp-metadata@8.1.2: + gcp-metadata@8.1.2(supports-color@10.2.2): dependencies: - gaxios: 7.1.5 + gaxios: 7.1.5(supports-color@10.2.2) google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -12045,11 +12225,11 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-uri@6.0.5: + get-uri@6.0.5(supports-color@10.2.2): dependencies: basic-ftp: 6.0.1 data-uri-to-buffer: 6.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -12113,12 +12293,12 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - google-auth-library@10.7.0: + google-auth-library@10.7.0(supports-color@10.2.2): dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5 - gcp-metadata: 8.1.2 + gaxios: 7.1.5(supports-color@10.2.2) + gcp-metadata: 8.1.2(supports-color@10.2.2) google-logging-utils: 1.1.3 jws: 4.0.1 transitivePeerDependencies: @@ -12210,33 +12390,33 @@ snapshots: http-link-header@1.1.3: {} - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - http-proxy@1.18.1: + http-proxy@1.18.1(debug@4.4.3(supports-color@10.2.2)): dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.16.0 + follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2)) requires-port: 1.0.0 transitivePeerDependencies: - debug - http-server@14.1.1: + http-server@14.1.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2): dependencies: basic-auth: 2.0.1 chalk: 4.1.2 corser: 2.0.1 he: 1.2.0 html-encoding-sniffer: 3.0.0 - http-proxy: 1.18.1 + http-proxy: 1.18.1(debug@4.4.3(supports-color@10.2.2)) mime: 1.6.0 minimist: 1.2.8 opener: 1.5.2 - portfinder: 1.0.38 + portfinder: 1.0.38(supports-color@10.2.2) secure-compare: 3.0.1 union: 0.5.0 url-join: 4.0.1 @@ -12244,10 +12424,10 @@ snapshots: - debug - supports-color - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -12515,18 +12695,18 @@ snapshots: dependencies: append-transform: 2.0.0 - istanbul-lib-instrument@4.0.3: + istanbul-lib-instrument@4.0.3(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color - istanbul-lib-instrument@6.0.3: + istanbul-lib-instrument@6.0.3(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/parser': 7.29.7 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 @@ -12549,18 +12729,18 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@4.0.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color - istanbul-lib-source-maps@5.0.6: + istanbul-lib-source-maps@5.0.6(supports-color@10.2.2): dependencies: '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -12594,10 +12774,10 @@ snapshots: jest-util: 30.4.1 p-limit: 3.1.0 - jest-circus@30.4.2: + jest-circus@30.4.2(supports-color@10.2.2): dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1 + '@jest/expect': 30.4.1(supports-color@10.2.2) '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 '@types/node': 25.9.2 @@ -12608,8 +12788,8 @@ snapshots: jest-each: 30.4.1 jest-matcher-utils: 30.4.1 jest-message-util: 30.4.1 - jest-runtime: 30.4.2 - jest-snapshot: 30.4.1 + jest-runtime: 30.4.2(supports-color@10.2.2) + jest-snapshot: 30.4.1(supports-color@10.2.2) jest-util: 30.4.1 p-limit: 3.1.0 pretty-format: 30.4.1 @@ -12620,15 +12800,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.4.2(@types/node@25.9.2): + jest-cli@30.4.2(@types/node@25.9.2)(supports-color@10.2.2): dependencies: - '@jest/core': 30.4.2 + '@jest/core': 30.4.2(supports-color@10.2.2) '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.4.2(@types/node@25.9.2) + jest-config: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) jest-util: 30.4.1 jest-validate: 30.4.1 yargs: 17.7.2 @@ -12639,25 +12819,25 @@ snapshots: - supports-color - ts-node - jest-config@30.4.2(@types/node@25.9.2): + jest-config@30.4.2(@types/node@25.9.2)(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@jest/get-type': 30.1.0 '@jest/pattern': 30.4.0 '@jest/test-sequencer': 30.4.1 '@jest/types': 30.4.1 - babel-jest: 30.4.1(@babel/core@7.29.7) + babel-jest: 30.4.1(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) chalk: 4.1.2 ci-info: 4.4.0 deepmerge: 4.3.1 glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 30.4.2 + jest-circus: 30.4.2(supports-color@10.2.2) jest-docblock: 30.4.0 jest-environment-node: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-runner: 30.4.2 + jest-runner: 30.4.2(supports-color@10.2.2) jest-util: 30.4.1 jest-validate: 30.4.1 parse-json: 5.2.0 @@ -12756,7 +12936,7 @@ snapshots: optionalDependencies: jest-resolve: 30.4.1 - jest-process-manager@0.4.0: + jest-process-manager@0.4.0(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@types/wait-on': 5.3.4 chalk: 4.1.2 @@ -12765,19 +12945,19 @@ snapshots: find-process: 1.4.11 prompts: 2.4.2 signal-exit: 3.0.7 - spawnd: 5.0.0 + spawnd: 5.0.0(supports-color@10.2.2) tree-kill: 1.2.2 - wait-on: 7.2.0 + wait-on: 7.2.0(debug@4.4.3(supports-color@10.2.2)) transitivePeerDependencies: - debug - supports-color jest-regex-util@30.4.0: {} - jest-resolve-dependencies@30.4.2: + jest-resolve-dependencies@30.4.2(supports-color@10.2.2): dependencies: jest-regex-util: 30.4.0 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -12792,12 +12972,12 @@ snapshots: slash: 3.0.0 unrs-resolver: 1.12.2 - jest-runner@30.4.2: + jest-runner@30.4.2(supports-color@10.2.2): dependencies: '@jest/console': 30.4.1 '@jest/environment': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 '@types/node': 25.9.2 chalk: 4.1.2 @@ -12810,7 +12990,7 @@ snapshots: jest-leak-detector: 30.4.1 jest-message-util: 30.4.1 jest-resolve: 30.4.1 - jest-runtime: 30.4.2 + jest-runtime: 30.4.2(supports-color@10.2.2) jest-util: 30.4.1 jest-watcher: 30.4.1 jest-worker: 30.4.1 @@ -12819,14 +12999,14 @@ snapshots: transitivePeerDependencies: - supports-color - jest-runtime@30.4.2: + jest-runtime@30.4.2(supports-color@10.2.2): dependencies: '@jest/environment': 30.4.1 '@jest/fake-timers': 30.4.1 - '@jest/globals': 30.4.1 + '@jest/globals': 30.4.1(supports-color@10.2.2) '@jest/source-map': 30.0.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 '@types/node': 25.9.2 chalk: 4.1.2 @@ -12839,7 +13019,7 @@ snapshots: jest-mock: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@10.2.2) jest-util: 30.4.1 slash: 3.0.0 strip-bom: 4.0.0 @@ -12850,19 +13030,19 @@ snapshots: dependencies: diffable-html: 4.1.0 - jest-snapshot@30.4.1: + jest-snapshot@30.4.1(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/generator': 7.29.7 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/types': 7.29.0 '@jest/expect-utils': 30.4.1 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@10.2.2) '@jest/types': 30.4.1 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@10.2.2)) chalk: 4.1.2 expect: 30.4.1 graceful-fs: 4.2.11 @@ -12894,11 +13074,11 @@ snapshots: leven: 3.1.0 pretty-format: 30.4.1 - jest-watch-typeahead@3.0.1(jest@30.4.2(@types/node@25.9.2)): + jest-watch-typeahead@3.0.1(jest@30.4.2(@types/node@25.9.2)(supports-color@10.2.2)): dependencies: ansi-escapes: 7.3.0 chalk: 5.6.2 - jest: 30.4.2(@types/node@25.9.2) + jest: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) jest-regex-util: 30.4.0 jest-watcher: 30.4.1 slash: 5.1.0 @@ -12924,12 +13104,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.4.2(@types/node@25.9.2): + jest@30.4.2(@types/node@25.9.2)(supports-color@10.2.2): dependencies: - '@jest/core': 30.4.2 + '@jest/core': 30.4.2(supports-color@10.2.2) '@jest/types': 30.4.1 import-local: 3.2.0 - jest-cli: 30.4.2(@types/node@25.9.2) + jest-cli: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13073,28 +13253,28 @@ snapshots: dependencies: immediate: 3.0.6 - lighthouse-logger@1.2.0: + lighthouse-logger@1.2.0(supports-color@10.2.2): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) marky: 1.3.0 transitivePeerDependencies: - supports-color - lighthouse-logger@2.0.2: + lighthouse-logger@2.0.2(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) marky: 1.3.0 transitivePeerDependencies: - supports-color lighthouse-stack-packs@1.12.2: {} - lighthouse@12.6.1: + lighthouse@12.6.1(supports-color@10.2.2): dependencies: '@paulirish/trace_engine': 0.0.53 '@sentry/node': 7.120.4 axe-core: 4.11.4 - chrome-launcher: 1.2.1 + chrome-launcher: 1.2.1(supports-color@10.2.2) configstore: 5.0.1 csp_evaluator: 1.1.5 devtools-protocol: 0.0.1467305 @@ -13103,14 +13283,14 @@ snapshots: intl-messageformat: 10.7.18 jpeg-js: 0.4.4 js-library-detector: 6.7.0 - lighthouse-logger: 2.0.2 + lighthouse-logger: 2.0.2(supports-color@10.2.2) lighthouse-stack-packs: 1.12.2 lodash-es: 4.18.1 lookup-closest-locale: 6.2.0 metaviewport-parser: 0.3.0 open: 8.4.2 parse-cache-control: 1.0.1 - puppeteer-core: 24.41.0 + puppeteer-core: 24.41.0(supports-color@10.2.2) robots-parser: 3.0.1 semver: 5.7.2 speedline-core: 1.4.3 @@ -13257,10 +13437,6 @@ snapshots: lz-string@1.5.0: {} - magic-string@0.25.9: - dependencies: - sourcemap-codec: 1.4.8 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -13438,7 +13614,7 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - nyc@15.1.0: + nyc@15.1.0(supports-color@10.2.2): dependencies: '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.6 @@ -13452,10 +13628,10 @@ snapshots: glob: 7.2.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 4.0.3 + istanbul-lib-instrument: 4.0.3(supports-color@10.2.2) istanbul-lib-processinfo: 2.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 4.0.1(supports-color@10.2.2) istanbul-reports: 3.2.0 make-dir: 3.1.0 node-preload: 0.2.1 @@ -13654,16 +13830,16 @@ snapshots: p-try@2.2.0: {} - pac-proxy-agent@7.2.0: + pac-proxy-agent@7.2.0(supports-color@10.2.2): dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.3 - get-uri: 6.0.5 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + debug: 4.4.3(supports-color@10.2.2) + get-uri: 6.0.5(supports-color@10.2.2) + http-proxy-agent: 7.0.2(supports-color@10.2.2) + https-proxy-agent: 7.0.6(supports-color@10.2.2) pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5 + socks-proxy-agent: 8.0.5(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -13760,10 +13936,10 @@ snapshots: optionalDependencies: fsevents: 2.3.2 - portfinder@1.0.38: + portfinder@1.0.38(supports-color@10.2.2): dependencies: async: 3.2.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -13831,16 +14007,16 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-agent@6.5.0: + proxy-agent@6.5.0(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + debug: 4.4.3(supports-color@10.2.2) + http-proxy-agent: 7.0.2(supports-color@10.2.2) + https-proxy-agent: 7.0.6(supports-color@10.2.2) lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0 + pac-proxy-agent: 7.2.0(supports-color@10.2.2) proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5 + socks-proxy-agent: 8.0.5(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -13855,11 +14031,11 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@24.41.0: + puppeteer-core@24.41.0(supports-color@10.2.2): dependencies: - '@puppeteer/browsers': 2.13.0 + '@puppeteer/browsers': 2.13.0(supports-color@10.2.2) chromium-bidi: 14.0.0(devtools-protocol@0.0.1595872) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) devtools-protocol: 0.0.1595872 typed-query-selector: 2.12.1 webdriver-bidi-protocol: 0.4.1 @@ -13902,10 +14078,10 @@ snapshots: dependencies: typescript: 6.0.3 - react-docgen@8.0.3: + react-docgen@8.0.3(supports-color@10.2.2): dependencies: - '@babel/core': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) '@babel/types': 7.29.7 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -14142,7 +14318,7 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.3 '@rolldown/binding-win32-x64-msvc': 1.0.3 - rollup-plugin-visualizer@7.0.1(rolldown@1.0.3)(rollup@2.80.0): + rollup-plugin-visualizer@7.0.1(rolldown@1.0.3)(rollup@4.62.2): dependencies: open: 11.0.0 picomatch: 4.0.4 @@ -14150,10 +14326,37 @@ snapshots: yargs: 18.0.0 optionalDependencies: rolldown: 1.0.3 - rollup: 2.80.0 + rollup: 4.62.2 - rollup@2.80.0: + rollup@4.62.2: + dependencies: + '@types/estree': 1.0.9 optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 fsevents: 2.3.3 run-applescript@7.1.0: {} @@ -14214,9 +14417,9 @@ snapshots: semver@7.8.4: {} - send@0.19.2: + send@0.19.2(supports-color@10.2.2): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 destroy: 1.2.0 encodeurl: 2.0.0 @@ -14239,12 +14442,12 @@ snapshots: serialize-javascript@7.0.5: {} - serve-static@1.16.3: + serve-static@1.16.3(supports-color@10.2.2): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.2 + send: 0.19.2(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -14357,10 +14560,10 @@ snapshots: simple-git-hooks@2.13.1: {} - simple-peer@9.11.1: + simple-peer@9.11.1(supports-color@10.2.2): dependencies: buffer: 6.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) err-code: 3.0.1 get-browser-rtc: 1.1.0 queue-microtask: 1.2.3 @@ -14389,10 +14592,10 @@ snapshots: smob@1.6.2: {} - socks-proxy-agent@8.0.5: + socks-proxy-agent@8.0.5(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -14422,8 +14625,6 @@ snapshots: dependencies: whatwg-url: 7.1.0 - sourcemap-codec@1.4.8: {} - spawn-wrap@2.0.0: dependencies: foreground-child: 2.0.0 @@ -14433,12 +14634,12 @@ snapshots: signal-exit: 3.0.7 which: 2.0.2 - spawnd@5.0.0: + spawnd@5.0.0(supports-color@10.2.2): dependencies: exit: 0.1.2 signal-exit: 3.0.7 tree-kill: 1.2.2 - wait-port: 0.2.14 + wait-port: 0.2.14(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -15039,14 +15240,14 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-pwa@1.3.0(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): + vite-plugin-pwa@1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2))(workbox-window@7.4.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) pretty-bytes: 6.1.1 tinyglobby: 0.2.16 vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) - workbox-build: 7.4.0(@types/babel__core@7.20.5) - workbox-window: 7.4.0 + workbox-build: 7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2) + workbox-window: 7.4.1 transitivePeerDependencies: - supports-color @@ -15100,9 +15301,9 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - wait-on@7.2.0: + wait-on@7.2.0(debug@4.4.3(supports-color@10.2.2)): dependencies: - axios: 1.16.0 + axios: 1.16.0(debug@4.4.3(supports-color@10.2.2)) joi: 18.2.1 lodash: 4.18.1 minimist: 1.2.8 @@ -15110,9 +15311,9 @@ snapshots: transitivePeerDependencies: - debug - wait-on@9.0.10: + wait-on@9.0.10(debug@4.4.3(supports-color@10.2.2)): dependencies: - axios: 1.16.0 + axios: 1.16.0(debug@4.4.3(supports-color@10.2.2)) joi: 18.2.1 lodash: 4.18.1 minimist: 1.2.8 @@ -15120,11 +15321,11 @@ snapshots: transitivePeerDependencies: - debug - wait-port@0.2.14: + wait-port@0.2.14(supports-color@10.2.2): dependencies: chalk: 2.4.2 commander: 3.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -15231,118 +15432,118 @@ snapshots: wordwrapjs@5.1.1: {} - workbox-background-sync@7.4.0: + workbox-background-sync@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-broadcast-update@7.4.0: + workbox-broadcast-update@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-build@7.4.0(@types/babel__core@7.20.5): + workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2): dependencies: '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) - '@babel/core': 7.29.7 - '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/runtime': 7.29.7 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0) - '@rollup/plugin-node-resolve': 15.3.1(rollup@2.80.0) - '@rollup/plugin-replace': 2.4.2(rollup@2.80.0) - '@rollup/plugin-terser': 0.4.4(rollup@2.80.0) - '@surma/rollup-plugin-off-main-thread': 2.2.3 + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(@types/babel__core@7.20.5)(rollup@4.62.2)(supports-color@10.2.2) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.2) + '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) + '@rollup/plugin-terser': 1.0.0(rollup@4.62.2) + '@trickfilm400/rollup-plugin-off-main-thread': 3.0.0-pre1 ajv: 8.20.0 common-tags: 1.8.2 + eta: 4.6.0 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 glob: 11.1.0 - lodash: 4.18.1 pretty-bytes: 5.6.0 - rollup: 2.80.0 + rollup: 4.62.2 source-map: 0.8.0-beta.0 stringify-object: 3.3.0 strip-comments: 2.0.1 tempy: 0.6.0 upath: 1.2.0 - workbox-background-sync: 7.4.0 - workbox-broadcast-update: 7.4.0 - workbox-cacheable-response: 7.4.0 - workbox-core: 7.4.0 - workbox-expiration: 7.4.0 - workbox-google-analytics: 7.4.0 - workbox-navigation-preload: 7.4.0 - workbox-precaching: 7.4.0 - workbox-range-requests: 7.4.0 - workbox-recipes: 7.4.0 - workbox-routing: 7.4.0 - workbox-strategies: 7.4.0 - workbox-streams: 7.4.0 - workbox-sw: 7.4.0 - workbox-window: 7.4.0 + workbox-background-sync: 7.4.1 + workbox-broadcast-update: 7.4.1 + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-google-analytics: 7.4.1 + workbox-navigation-preload: 7.4.1 + workbox-precaching: 7.4.1 + workbox-range-requests: 7.4.1 + workbox-recipes: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + workbox-streams: 7.4.1 + workbox-sw: 7.4.1 + workbox-window: 7.4.1 transitivePeerDependencies: - '@types/babel__core' - supports-color - workbox-cacheable-response@7.4.0: + workbox-cacheable-response@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-core@7.4.0: {} + workbox-core@7.4.1: {} - workbox-expiration@7.4.0: + workbox-expiration@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-google-analytics@7.4.0: + workbox-google-analytics@7.4.1: dependencies: - workbox-background-sync: 7.4.0 - workbox-core: 7.4.0 - workbox-routing: 7.4.0 - workbox-strategies: 7.4.0 + workbox-background-sync: 7.4.1 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-navigation-preload@7.4.0: + workbox-navigation-preload@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-precaching@7.4.0: + workbox-precaching@7.4.1: dependencies: - workbox-core: 7.4.0 - workbox-routing: 7.4.0 - workbox-strategies: 7.4.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-range-requests@7.4.0: + workbox-range-requests@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-recipes@7.4.0: + workbox-recipes@7.4.1: dependencies: - workbox-cacheable-response: 7.4.0 - workbox-core: 7.4.0 - workbox-expiration: 7.4.0 - workbox-precaching: 7.4.0 - workbox-routing: 7.4.0 - workbox-strategies: 7.4.0 + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-precaching: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-routing@7.4.0: + workbox-routing@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-strategies@7.4.0: + workbox-strategies@7.4.1: dependencies: - workbox-core: 7.4.0 + workbox-core: 7.4.1 - workbox-streams@7.4.0: + workbox-streams@7.4.1: dependencies: - workbox-core: 7.4.0 - workbox-routing: 7.4.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 - workbox-sw@7.4.0: {} + workbox-sw@7.4.1: {} - workbox-window@7.4.0: + workbox-window@7.4.1: dependencies: '@types/trusted-types': 2.0.7 - workbox-core: 7.4.0 + workbox-core: 7.4.1 workerd@1.20260609.1: optionalDependencies: @@ -15449,19 +15650,6 @@ snapshots: lib0: 0.2.117 yjs: 13.6.31 - y-webrtc@10.3.0(yjs@13.6.31): - dependencies: - lib0: 0.2.117 - simple-peer: 9.11.1 - y-protocols: 1.0.7(yjs@13.6.31) - yjs: 13.6.31 - optionalDependencies: - ws: 8.21.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - y18n@4.0.3: {} y18n@5.0.8: {} diff --git a/scripts/verify-vendor-fork.mjs b/scripts/verify-vendor-fork.mjs new file mode 100644 index 00000000..3143e369 --- /dev/null +++ b/scripts/verify-vendor-fork.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env node +/** + * Static invariant guard for the vendored y-webrtc fork (`packages/collab-transport`). + * Wired into the CI security job as `verify:vendor` — fails the build if any of the + * three SC security patches or the fork bookkeeping drifts. See VENDOR-FORKS.md + issue #60. + */ +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = join(fileURLToPath(new URL('.', import.meta.url)), '..'); +const forkDir = join(root, 'packages', 'collab-transport'); + +const failures = []; +const check = (name, ok) => { + console.log(`${ok ? '✓' : '✗'} ${name}`); + if (!ok) failures.push(name); +}; + +const cryptoSrc = readFileSync(join(forkDir, 'src', 'crypto.js'), 'utf8'); +const webrtcSrc = readFileSync(join(forkDir, 'src', 'y-webrtc.js'), 'utf8'); +const pkg = JSON.parse(readFileSync(join(forkDir, 'package.json'), 'utf8')); +const rootPkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')); +const workspace = readFileSync(join(root, 'pnpm-workspace.yaml'), 'utf8'); + +// ── Invariant 1: PBKDF2 iterations stay at the OWASP 2024 SHA-256 minimum ────── +check( + 'PBKDF2 iterations == 600000', + /iterations:\s*600000/.test(cryptoSrc) && !/iterations:\s*100000/.test(cryptoSrc), +); + +// ── Invariant 2: derived CryptoKeys are non-extractable ─────────────────────── +check( + 'deriveKey extractable: false', + /\n\s*false,\s*\n\s*\['encrypt', 'decrypt'\]/.test(cryptoSrc), +); + +// ── Invariant 3: decrypt() returns the rejection (no silent swallow) ────────── +check('decrypt() returns promise.reject()', /return promise\.reject\(/.test(cryptoSrc)); + +// ── Invariant 4: DataChannel payloads are encrypted/decrypted ───────────────── +check( + 'DataChannel encrypt/decrypt applied', + /cryptoutils\.encrypt\(/.test(webrtcSrc) && /cryptoutils\.decrypt\(/.test(webrtcSrc), +); + +// ── Invariant 5: fork version carries the -scN suffix ───────────────────────── +check('fork version matches -scN', /^\d+\.\d+\.\d+-sc\d+$/.test(pkg.version)); + +// ── Invariant 6: no dangling upstream dependency / pnpm patch ───────────────── +const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies }; +check('root package.json has no y-webrtc dependency', !('y-webrtc' in deps)); +check('pnpm-workspace has no y-webrtc patchedDependency', !workspace.includes('y-webrtc@')); +check('deprecated patch file removed', !existsSync(join(root, 'patches', 'y-webrtc@10.3.0.patch'))); + +if (failures.length > 0) { + console.error(`\nverify:vendor FAILED — ${failures.length} invariant(s) violated:`); + for (const f of failures) console.error(` - ${f}`); + process.exit(1); +} +console.log(`\nverify:vendor OK — @domain/collab-transport@${pkg.version} invariants hold.`); From 378dc70849334e3df388b5796ac513c8b7c939e5 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:48:05 +0200 Subject: [PATCH 06/14] chore(settings): clean stale search hints, MaturityBadge in ProForge - Experimental-category search hints referenced retired/promoted flags (plot board, codex, cross project); replaced with current features. - ProForgeDashboard uses the catalog-driven MaturityBadge instead of a hard-coded Experimental pill (v1.24 maturity-label convention). - AGENTS.md drift: six opt-in flags (enableProForge), 19 locales. --- AGENTS.md | 10 +++++----- components/proForge/ProForgeDashboard.tsx | 7 ++++--- services/settingsSearchHints.ts | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b1ab2a67..f374c9fd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,7 +14,7 @@ - **Version:** `1.23.0` - **License:** MIT -The app supports a multi-provider AI stack (Gemini, OpenAI, Claude, Grok, OpenRouter, Ollama, WebLLM, ONNX Runtime Web, Transformers.js), four AI execution modes (Hybrid / Cloud / Local / Eco), real-time collaboration with E2E encryption, a Plot Board v2 with swimlane/canvas/timeline modes, character/world management, manuscript export, voice dictation, and an 11-locale i18n layer. +The app supports a multi-provider AI stack (Gemini, OpenAI, Claude, Grok, OpenRouter, Ollama, WebLLM, ONNX Runtime Web, Transformers.js), four AI execution modes (Hybrid / Cloud / Local / Eco), real-time collaboration with E2E encryption, a Plot Board v2 with swimlane/canvas/timeline modes, character/world management, manuscript export, voice dictation, and a 19-locale i18n layer. --- @@ -114,7 +114,7 @@ WorldScript-Studio/ │ ├── collab-transport/ # Vendor fork of y-webrtc 10.3.0 with E2E encryption patch │ ├── ui/ # Tailwind preset + design tokens │ └── worker-bus/ # Typed worker pool, circuit breakers, dead-letter queue -├── locales/ # i18n source JSON modules (11 locales) +├── locales/ # i18n source JSON modules (19 locales) ├── public/ # Static assets; runtime i18n bundles `public/locales//bundle.json` ├── tests/ │ ├── unit/ # Vitest tests (co-located naming convention) @@ -387,7 +387,7 @@ Edge builds run `scripts/build-edge.mjs` which sets `DEPLOY_TARGET=edge` and pat ### Feature Flags -- `features/featureFlags/featureFlagsSlice.ts` gates **23 flags**. New installs get the **full feature set**: all default **on** except five opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix. +- `features/featureFlags/featureFlagsSlice.ts` gates **23 flags**. New installs get the **full feature set**: all default **on** except six opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix. - UI: Settings → Experimental flags. - Do not use scattered `if (true)` hacks. @@ -486,10 +486,10 @@ Central orchestration layer for all background worker tasks. Messages use short ## Internationalization (i18n) - **Custom React Context** (`contexts/I18nContext.tsx`) — not i18next. -- Source modules: `locales//*.json` for **11 locales**: `ar`, `de`, `el`, `en`, `es`, `fr`, `he`, `it`, `ja`, `pt`, `zh`. +- Source modules: `locales//*.json` for **19 locales**: `ar`, `de`, `el`, `en`, `es`, `eu`, `fa`, `fi`, `fr`, `he`, `hu`, `is`, `it`, `ja`, `ko`, `pt`, `ru`, `sv`, `zh`. - Runtime bundles: `public/locales//bundle.json` (rebuilt by `pnpm run i18n:bundle` or automatically via `predev` / `prebuild`). - Hook: `useTranslation()` returns `t('key.path')`. **No hardcoded text** in UI. -- Key parity is enforced in CI (`pnpm run i18n:check`). Add keys to **all eleven** locale trees. +- Key parity is enforced in CI (`pnpm run i18n:check`). Add keys to **all nineteen** locale trees. - Repair scripts: `services/i18nBootstrap.ts` and `services/i18nRepair.ts` handle missing keys / bundle corruption. - RTL Beta: Arabic (`ar`) and Hebrew (`he`) set `html[dir="rtl"]`. Layout mirroring uses logical properties and a global `[dir="rtl"]` CSS net. Canvas/SVG boards (Plot Board, Character Graph) stay LTR to keep pointer/geometry math correct. `enableRtlLayout` flag forces RTL for testing. diff --git a/components/proForge/ProForgeDashboard.tsx b/components/proForge/ProForgeDashboard.tsx index 846b4e47..ee50514a 100644 --- a/components/proForge/ProForgeDashboard.tsx +++ b/components/proForge/ProForgeDashboard.tsx @@ -7,7 +7,7 @@ import type React from 'react'; import { useCallback, useState } from 'react'; import { useProForgeViewContext } from '../../contexts/ProForgeViewContext'; import { PIPELINE_STAGES, type PipelineStage } from '../../features/proForge/types'; -import { Badge } from '../ui/Badge'; +import { MaturityBadge } from '../settings/MaturityBadge'; import { PipelineProgressPanel } from './PipelineProgressPanel'; import { PipelineReviewPanel } from './PipelineReviewPanel'; @@ -88,8 +88,9 @@ export const ProForgeDashboard: React.FC = () => {

    {t('proforge.pipeline.title')}

    - {/* QNBS-v3: ProForge is an on-by-default but experimental agentic pipeline — label it. */} - {t('common.badge.experimental')} + {/* QNBS-v3: ProForge is opt-in + experimental — label driven by FEATURE_CATALOG so it + can never drift from the catalog/slice (MaturityBadge convention, v1.24). */} +
    {/* QNBS-v3: PR6 — make the human-in-the-loop expectation explicit, not just implied in help. */}

    diff --git a/services/settingsSearchHints.ts b/services/settingsSearchHints.ts index 6510a87b..b519cddd 100644 --- a/services/settingsSearchHints.ts +++ b/services/settingsSearchHints.ts @@ -53,13 +53,13 @@ export const SETTINGS_CATEGORY_SEARCH_HINTS: Record = { guide: ['overview', 'help', 'map', 'categories', 'leitfaden'], experimental: [ 'feature flag', - 'plot board', 'duckdb', 'mind map', 'objects', 'interviews', - 'codex', - 'cross project', + 'proforge', + 'local first', + 'copilot', ], 'lora-adapters': ['lora', 'adapter', 'safetensors', 'fine-tune', 'fine tune', 'local model'], plugins: ['plugin', 'extension', 'esm', 'sandboxed', 'capability', 'permissions'], From 5d4c0efbe90c739e7ee3ada71dda9a78c5d51c9e Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:48:10 +0200 Subject: [PATCH 07/14] docs: changelog entries for #266 and #60 under [Unreleased] --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 568c6a99..ed93850d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **Settings hygiene.** Removed stale Experimental-category search hints (`plot board`, `codex`, + `cross project` — retired/promoted flags) in favor of current features; `ProForgeDashboard` now + uses the catalog-driven `MaturityBadge` instead of a hard-coded Experimental pill, keeping the + v1.24 maturity-label convention consistent. + - **Desktop settings "minimize to tray" is now a proper switch.** `DesktopSection` used the only raw `` left in Settings, with its hint not programmatically associated. It now renders the design-system `ToggleSwitch` (`role="switch"`, `aria-labelledby` + `aria-describedby` @@ -105,11 +110,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **Ollama / LM Studio / vLLM discovery & connectivity on desktop, CORS noise in the PWA + (#266).** Root cause: all local-server traffic (`services/ollamaService.ts`, + `scanLocalOpenAiCompatibleEndpoints()`) used the WebView's `fetch`, so inside the Tauri shell the + cross-origin `localhost` requests died on CORS/PNA, and in the PWA the settings auto-effect probed + `localhost:11434` on every visit (loud CORS console errors). All local-server calls now go through + the new thin `services/localServerHttp.ts`, which routes via `@tauri-apps/plugin-http` (native, + CORS-free) on desktop and keeps browser `fetch` on the web, with shared URL normalization, timeout + composition and `unreachable`/`timeout` classification (user aborts still propagate unchanged). + The Settings → AI card no longer auto-probes localhost in the PWA — it shows a quiet "desktop app + required" banner with a download CTA instead — and the desktop scan gained per-endpoint status + badges (reachable / no response / timeout / HTTP error) plus a one-click **Use this URL** action. + All new strings localized in 19 locales. See + [ADR 0012](docs/adr/0012-local-server-connectivity-tauri-http.md) and + [`docs/LOCAL-AI.md`](docs/LOCAL-AI.md). + - **Feature-catalog / slice default drift made structurally impossible.** `features/featureCatalog.ts` now covers all **23** flags (was 16) and **derives** each entry's `defaultOn` from the slice's `defaultFeatureFlagsState` instead of hand-keying it — the class of bug where the catalog said `false` while the slice said `true` for ~12 flags can no longer recur (guarded by the new `tests/unit/featureCatalog.test.ts`). Added risk-level / desktop-requirement / dependency metadata. + +### Security + +- **Tauri HTTP-plugin capability scope pinned (#266).** `http:default` alone grants **no** URL + scope — every plugin-http call (including AI-SDK cloud calls on desktop) was silently denied by + the plugin's allow-list check. The capability now explicitly allows loopback any-port + (`http://localhost:*/*`, `http://127.0.0.1:*/*` — Ollama/LM Studio/vLLM + custom ports) and the + cloud endpoints mirroring the Tauri CSP `connect-src` (Gemini, OpenAI, x.ai, OpenRouter, Groq). +- **y-webrtc vendor-fork audit + CI invariant guard (#60).** Full-file diff of + `packages/collab-transport` against upstream `y-webrtc@10.3.0`: no deviations beyond the three + documented SC patches (PBKDF2 600k iterations, `extractable: false`, `return promise.reject`) plus + the DataChannel E2E encryption — recorded in `packages/collab-transport/AUDIT.md`, fork bumped to + `10.3.0-sc2`. The deprecated `patches/y-webrtc@10.3.0.patch` and the dead root `y-webrtc` + dependency (zero imports) are removed, and the previously-referenced-but-missing + `scripts/verify-vendor-fork.mjs` now exists and runs in the CI security job (`verify:vendor`). + ### Removed - **Dead `enableWebnnInference` feature flag removed.** The flag shipped default-on but **no runtime From 562d010d0e20d8c73d2d8dfa9b27369f81073a79 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 10:07:02 +0200 Subject: [PATCH 08/14] fix(security): raise pnpm overrides for 9 high-severity advisories The CI security gate (pnpm audit --audit-level=high) started failing on every PR: 9 high advisories in transitive dev paths. Overrides raised to the patched lines (bounded to avoid unvetted major jumps): adm-zip >=0.6.0, axios >=1.18.0, brace-expansion >=5.0.8, fast-uri >=3.1.4 <4, js-yaml >=4.3.0 <5, postcss >=8.5.18, sharp >=0.35.0. Also reverts an accidental packageManager pin to pnpm@11.17.0 (back to 11.5.2). --- package.json | 2 +- pnpm-lock.yaml | 1446 ++++++++++++++++++++++--------------------- pnpm-workspace.yaml | 12 +- 3 files changed, 761 insertions(+), 699 deletions(-) diff --git a/package.json b/package.json index 95c4d305..298271b2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "tauri" ], "type": "module", - "packageManager": "pnpm@11.17.0", + "packageManager": "pnpm@11.5.2", "engines": { "node": ">=22.0.0", "pnpm": ">=11.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db930aef..a545bab5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,19 +15,22 @@ overrides: tmp: '>=0.2.7' '@xmldom/xmldom': '>=0.8.13' protobufjs: '>=8.4.1' - axios: '>=1.15.2' + axios: '>=1.18.0' basic-ftp: '>=5.3.1' - fast-uri: '>=3.1.2' + fast-uri: '>=3.1.4 <4' ip-address: '>=10.1.1' ws: '>=8.21.0' form-data: '>=4.0.6' - brace-expansion: '>=5.0.6' + brace-expansion: '>=5.0.8' uuid: '>=11.1.1' qs: '>=6.15.2' dompurify: '>=3.4.11' '@babel/core': '>=7.29.6' undici: '>=7.28.0 <8' - js-yaml: '>=4.1.2' + js-yaml: '>=4.3.0 <5' + adm-zip: '>=0.6.0' + postcss: '>=8.5.18' + sharp: '>=0.35.0' patchedDependencies: zod@4.4.3: 338616f6b312752cd87f1779a712517e6ffff9fc470a3f3e69d1cdc5a8ca0d93 @@ -89,7 +92,7 @@ importers: version: 5.2.8 '@google/genai': specifier: ^2.8.0 - version: 2.8.0(supports-color@10.2.2) + version: 2.8.0 '@reduxjs/toolkit': specifier: ^2.12.0 version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) @@ -204,22 +207,22 @@ importers: version: 10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) '@storybook/react': specifier: ^10.4.5 - version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3) + version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3) '@storybook/react-vite': specifier: ^10.4.5 - version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) '@storybook/test-runner': specifier: ^0.24.4 - version: 0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(debug@4.4.3(supports-color@10.2.2))(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2) + version: 0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2) '@stryker-mutator/core': specifier: ^9.2.0 - version: 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) + version: 9.6.1(@types/node@25.9.2) '@stryker-mutator/typescript-checker': specifier: ^9.6.1 - version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(typescript@6.0.3) + version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(typescript@6.0.3) '@stryker-mutator/vitest-runner': specifier: ^9.2.0 - version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(vitest@4.1.9) + version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(vitest@4.1.9) '@tailwindcss/vite': specifier: ^4.3.0 version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -264,7 +267,7 @@ importers: version: 6.2.5 http-server: specifier: ^14.1.1 - version: 14.1.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) + version: 14.1.1(supports-color@10.2.2) jsdom: specifier: ^29.1.1 version: 29.1.1 @@ -294,16 +297,16 @@ importers: version: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) vite-plugin-pwa: specifier: ^1.3.0 - version: 1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2))(workbox-window@7.4.1) + version: 1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1) vitest: specifier: ^4.1.9 version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) wait-on: specifier: ^9.0.10 - version: 9.0.10(debug@4.4.3(supports-color@10.2.2)) + version: 9.0.10 wrangler: specifier: ^4.99.0 - version: 4.99.0 + version: 4.99.0(@types/node@25.9.2) y-protocols: specifier: ^1.0.7 version: 1.0.7(yjs@13.6.31) @@ -312,7 +315,7 @@ importers: optionalDependencies: '@huggingface/transformers': specifier: ^4.2.0 - version: 4.2.0 + version: 4.2.0(@types/node@25.9.2) '@mlc-ai/web-llm': specifier: ^0.2.84 version: 0.2.84 @@ -1308,8 +1311,8 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.11.0': - resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} '@emnapi/runtime@1.9.2': resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} @@ -1558,152 +1561,161 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -3474,9 +3486,13 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - adm-zip@0.5.17: - resolution: {integrity: sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==} - engines: {node: '>=12.0'} + adm-zip@0.6.0: + resolution: {integrity: sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==} + engines: {node: '>=14.0'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} @@ -3644,8 +3660,8 @@ packages: resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} engines: {node: '>=4'} - axios@1.16.0: - resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} + axios@1.18.1: + resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==} b4a@1.8.0: resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} @@ -3783,9 +3799,9 @@ packages: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} @@ -4596,11 +4612,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fast-uri@4.0.0: - resolution: {integrity: sha512-l90y339r2DkZs/ldcWQXcwTjkbp/NbuJDGYoQ3awBgaT3GXOFkm3OkVpz6Z86TywYcya0eVP2r1kTV90f3krGQ==} + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} @@ -4951,6 +4964,10 @@ packages: engines: {node: '>=12'} hasBin: true + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -5465,8 +5482,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true jsdom@29.1.1: @@ -5886,8 +5903,8 @@ packages: resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} engines: {node: ^20.17.0 || >=22.9.0} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -6215,8 +6232,8 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} powershell-utils@0.1.0: @@ -6607,6 +6624,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.2: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} @@ -6644,9 +6666,14 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -7834,16 +7861,16 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7(supports-color@10.2.2)': + '@babel/core@7.29.7': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 @@ -7886,42 +7913,42 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.7 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 debug: 4.4.3(supports-color@10.2.2) @@ -7932,33 +7959,33 @@ snapshots: '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5(supports-color@10.2.2)': + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-member-expression-to-functions@7.29.7(supports-color@10.2.2)': + '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7(supports-color@10.2.2)': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color @@ -7974,43 +8001,43 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-wrap-function': 7.29.7(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-wrap-function': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1(supports-color@10.2.2)': + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@10.2.2)': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -8027,10 +8054,10 @@ snapshots: '@babel/helper-validator-option@7.29.7': {} - '@babel/helper-wrap-function@7.29.7(supports-color@10.2.2)': + '@babel/helper-wrap-function@7.29.7': dependencies: '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -8048,628 +8075,628 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-globals': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/template': 7.29.7 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/preset-env@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/preset-env@7.29.7(@babel/core@7.29.7)': dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2)) - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) core-js-compat: 3.49.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/types': 7.29.7 esutils: 2.0.3 - '@babel/preset-typescript@7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.7) transitivePeerDependencies: - supports-color @@ -8689,7 +8716,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7(supports-color@10.2.2)': + '@babel/traverse@7.29.7': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -8851,7 +8878,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.0': + '@emnapi/runtime@1.11.3': dependencies: tslib: 2.8.1 optional: true @@ -8984,9 +9011,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@google/genai@2.8.0(supports-color@10.2.2)': + '@google/genai@2.8.0': dependencies: - google-auth-library: 10.7.0(supports-color@10.2.2) + google-auth-library: 10.7.0 p-retry: 4.6.2 protobufjs: 8.6.1 ws: 8.21.0 @@ -9017,109 +9044,121 @@ snapshots: '@huggingface/tokenizers@0.1.3': optional: true - '@huggingface/transformers@4.2.0': + '@huggingface/transformers@4.2.0(@types/node@25.9.2)': dependencies: '@huggingface/jinja': 0.5.9 '@huggingface/tokenizers': 0.1.3 onnxruntime-node: 1.24.3 onnxruntime-web: 1.26.0-dev.20260416-b7804b056c - sharp: 0.34.5 + sharp: 0.35.3(@types/node@25.9.2) + transitivePeerDependencies: + - '@types/node' optional: true '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.2 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.2 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.2': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.2': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.2': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.2': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + optional: true + + '@img/sharp-linux-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.2 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.2 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.2 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.2 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.2 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.2 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.3': dependencies: - '@emnapi/runtime': 1.11.0 + '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-arm64@0.35.3': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-ia32@0.35.3': + optional: true + + '@img/sharp-win32-x64@0.35.3': optional: true '@inquirer/ansi@2.0.5': {} @@ -9257,7 +9296,7 @@ snapshots: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 4.2.0 + js-yaml: 4.3.0 resolve-from: 5.0.0 '@istanbuljs/schema@0.1.6': {} @@ -9277,7 +9316,7 @@ snapshots: '@jest/pattern': 30.4.0 '@jest/reporters': 30.4.1(supports-color@10.2.2) '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@jest/transform': 30.4.1 '@jest/types': 30.4.1 '@types/node': 25.9.2 ansi-escapes: 4.3.2 @@ -9287,15 +9326,15 @@ snapshots: fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 jest-changed-files: 30.4.1 - jest-config: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) + jest-config: 30.4.2(@types/node@25.9.2) jest-haste-map: 30.4.1 jest-message-util: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-resolve-dependencies: 30.4.2(supports-color@10.2.2) - jest-runner: 30.4.2(supports-color@10.2.2) - jest-runtime: 30.4.2(supports-color@10.2.2) - jest-snapshot: 30.4.1(supports-color@10.2.2) + jest-resolve-dependencies: 30.4.2 + jest-runner: 30.4.2 + jest-runtime: 30.4.2 + jest-snapshot: 30.4.1 jest-util: 30.4.1 jest-validate: 30.4.1 jest-watcher: 30.4.1 @@ -9324,10 +9363,10 @@ snapshots: dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@30.4.1(supports-color@10.2.2)': + '@jest/expect@30.4.1': dependencies: expect: 30.4.1 - jest-snapshot: 30.4.1(supports-color@10.2.2) + jest-snapshot: 30.4.1 transitivePeerDependencies: - supports-color @@ -9342,10 +9381,10 @@ snapshots: '@jest/get-type@30.1.0': {} - '@jest/globals@30.4.1(supports-color@10.2.2)': + '@jest/globals@30.4.1': dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1(supports-color@10.2.2) + '@jest/expect': 30.4.1 '@jest/types': 30.4.1 jest-mock: 30.4.1 transitivePeerDependencies: @@ -9361,7 +9400,7 @@ snapshots: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@jest/transform': 30.4.1 '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 '@types/node': 25.9.2 @@ -9371,7 +9410,7 @@ snapshots: glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3(supports-color@10.2.2) + istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6(supports-color@10.2.2) istanbul-reports: 3.2.0 @@ -9415,12 +9454,12 @@ snapshots: jest-haste-map: 30.4.1 slash: 3.0.0 - '@jest/transform@30.4.1(supports-color@10.2.2)': + '@jest/transform@30.4.1': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 7.0.1(supports-color@10.2.2) + babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 @@ -9484,7 +9523,7 @@ snapshots: '@lhci/cli@0.15.1(supports-color@10.2.2)': dependencies: '@lhci/utils': 0.15.1(supports-color@10.2.2) - chrome-launcher: 1.2.1(supports-color@10.2.2) + chrome-launcher: 1.2.1 compression: 1.8.1(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2) express: 4.22.1(supports-color@10.2.2) @@ -9493,7 +9532,7 @@ snapshots: lighthouse: 12.6.1(supports-color@10.2.2) lighthouse-logger: 1.2.0(supports-color@10.2.2) open: 7.4.2 - proxy-agent: 6.5.0(supports-color@10.2.2) + proxy-agent: 6.5.0 tmp: 0.2.7 uuid: 14.0.0 yargs: 15.4.1 @@ -9511,7 +9550,7 @@ snapshots: dependencies: debug: 4.4.3(supports-color@10.2.2) isomorphic-fetch: 3.0.0 - js-yaml: 4.2.0 + js-yaml: 4.3.0 lighthouse: 12.6.1(supports-color@10.2.2) tree-kill: 1.2.2 transitivePeerDependencies: @@ -9704,7 +9743,7 @@ snapshots: debug: 4.4.3(supports-color@10.2.2) extract-zip: 2.0.1(supports-color@10.2.2) progress: 2.0.3 - proxy-agent: 6.5.0(supports-color@10.2.2) + proxy-agent: 6.5.0 semver: 7.8.4 tar-fs: 3.1.2 yargs: 17.7.2 @@ -9777,10 +9816,10 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(@types/babel__core@7.20.5)(rollup@4.62.2)(supports-color@10.2.2)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.2)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 '@rollup/pluginutils': 5.4.0(rollup@4.62.2) optionalDependencies: '@types/babel__core': 7.20.5 @@ -9992,16 +10031,16 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@storybook/react-vite@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + '@storybook/react-vite@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) '@rollup/pluginutils': 5.4.0(rollup@4.62.2) '@storybook/builder-vite': 10.4.5(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) - '@storybook/react': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3) + '@storybook/react': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3) empathic: 2.0.1 magic-string: 0.30.21 react: 19.2.7 - react-docgen: 8.0.3(supports-color@10.2.2) + react-docgen: 8.0.3 react-dom: 19.2.7(react@19.2.7) resolve: 1.22.12 storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -10016,12 +10055,12 @@ snapshots: - typescript - webpack - '@storybook/react@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)(typescript@6.0.3)': + '@storybook/react@10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 '@storybook/react-dom-shim': 10.4.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) react: 19.2.7 - react-docgen: 8.0.3(supports-color@10.2.2) + react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@6.0.3) react-dom: 19.2.7(react@19.2.7) storybook: 10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -10032,9 +10071,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/test-runner@0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(debug@4.4.3(supports-color@10.2.2))(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)': + '@storybook/test-runner@0.24.4(@swc/helpers@0.5.21)(@types/node@25.9.2)(storybook@10.4.5(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/generator': 7.29.1 '@babel/template': 7.28.6 '@babel/types': 7.29.0 @@ -10043,13 +10082,13 @@ snapshots: '@swc/jest': 0.2.39(@swc/core@1.15.33(@swc/helpers@0.5.21)) expect-playwright: 0.8.0 jest: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) - jest-circus: 30.4.2(supports-color@10.2.2) + jest-circus: 30.4.2 jest-environment-node: 30.4.1 jest-junit: 16.0.0 - jest-process-manager: 0.4.0(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) - jest-runner: 30.4.2(supports-color@10.2.2) + jest-process-manager: 0.4.0(supports-color@10.2.2) + jest-runner: 30.4.2 jest-serializer-html: 7.1.0 - jest-watch-typeahead: 3.0.1(jest@30.4.2(@types/node@25.9.2)(supports-color@10.2.2)) + jest-watch-typeahead: 3.0.1(jest@30.4.2(@types/node@25.9.2)) nyc: 15.1.0(supports-color@10.2.2) playwright: 1.61.0 playwright-core: 1.61.0 @@ -10073,11 +10112,11 @@ snapshots: tslib: 2.8.1 typed-inject: 5.0.0 - '@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2)': + '@stryker-mutator/core@9.6.1(@types/node@25.9.2)': dependencies: '@inquirer/prompts': 8.4.2(@types/node@25.9.2) '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/instrumenter': 9.6.1(supports-color@10.2.2) + '@stryker-mutator/instrumenter': 9.6.1 '@stryker-mutator/util': 9.6.1 ajv: 8.18.0 chalk: 5.6.2 @@ -10105,14 +10144,14 @@ snapshots: - '@types/node' - supports-color - '@stryker-mutator/instrumenter@9.6.1(supports-color@10.2.2)': + '@stryker-mutator/instrumenter@9.6.1': dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/generator': 7.29.1 '@babel/parser': 7.29.3 - '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.7) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.7) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) '@stryker-mutator/api': 9.6.1 '@stryker-mutator/util': 9.6.1 angular-html-parser: 10.4.0 @@ -10122,20 +10161,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@stryker-mutator/typescript-checker@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(typescript@6.0.3)': + '@stryker-mutator/typescript-checker@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(typescript@6.0.3)': dependencies: '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/core': 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) + '@stryker-mutator/core': 9.6.1(@types/node@25.9.2) '@stryker-mutator/util': 9.6.1 semver: 7.7.4 typescript: 6.0.3 '@stryker-mutator/util@9.6.1': {} - '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2)(supports-color@10.2.2))(vitest@4.1.9)': + '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@25.9.2))(vitest@4.1.9)': dependencies: '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/core': 9.6.1(@types/node@25.9.2)(supports-color@10.2.2) + '@stryker-mutator/core': 9.6.1(@types/node@25.9.2) '@stryker-mutator/util': 9.6.1 semver: 7.7.4 tslib: 2.8.1 @@ -10760,9 +10799,15 @@ snapshots: acorn@8.17.0: {} - adm-zip@0.5.17: + adm-zip@0.6.0: optional: true + agent-base@6.0.2: + dependencies: + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} aggregate-error@3.1.0: @@ -10789,14 +10834,14 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 4.0.0 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -10922,35 +10967,37 @@ snapshots: axe-core@4.12.1: {} - axios@1.16.0(debug@4.4.3(supports-color@10.2.2)): + axios@1.18.1: dependencies: - follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2)) + follow-redirects: 1.16.0 form-data: 4.0.6 + https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color b4a@1.8.0: {} - babel-jest@30.4.1(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + babel-jest@30.4.1(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@jest/transform': 30.4.1 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 7.0.1(supports-color@10.2.2) - babel-preset-jest: 30.4.0(@babel/core@7.29.7(supports-color@10.2.2)) + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.4.0(@babel/core@7.29.7) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@7.0.1(supports-color@10.2.2): + babel-plugin-istanbul@7.0.1: dependencies: '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.6 - istanbul-lib-instrument: 6.0.3(supports-color@10.2.2) + istanbul-lib-instrument: 6.0.3 test-exclude: 6.0.0 transitivePeerDependencies: - supports-color @@ -10959,54 +11006,54 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7): dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7(supports-color@10.2.2)): - dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) - - babel-preset-jest@30.4.0(@babel/core@7.29.7(supports-color@10.2.2)): - dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) + + babel-preset-jest@30.4.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 babel-plugin-jest-hoist: 30.4.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@10.2.2)) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) balanced-match@4.0.4: {} @@ -11087,7 +11134,7 @@ snapshots: boolean@3.2.0: optional: true - brace-expansion@5.0.6: + brace-expansion@5.0.8: dependencies: balanced-match: 4.0.4 @@ -11203,12 +11250,12 @@ snapshots: check-error@2.1.3: {} - chrome-launcher@1.2.1(supports-color@10.2.2): + chrome-launcher@1.2.1: dependencies: '@types/node': 25.9.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 - lighthouse-logger: 2.0.2(supports-color@10.2.2) + lighthouse-logger: 2.0.2 transitivePeerDependencies: - supports-color @@ -11934,7 +11981,7 @@ snapshots: range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2(supports-color@10.2.2) - serve-static: 1.16.3(supports-color@10.2.2) + serve-static: 1.16.3 setprototypeof: 1.2.0 statuses: 2.0.2 type-is: 1.6.18 @@ -11981,9 +12028,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: {} - - fast-uri@4.0.0: {} + fast-uri@3.1.4: {} fast-wrap-ansi@0.2.0: dependencies: @@ -12073,9 +12118,7 @@ snapshots: kapsule: 1.16.3 preact: 10.29.1 - follow-redirects@1.16.0(debug@4.4.3(supports-color@10.2.2)): - optionalDependencies: - debug: 4.4.3(supports-color@10.2.2) + follow-redirects@1.16.0: {} for-each@0.3.5: dependencies: @@ -12160,17 +12203,17 @@ snapshots: functions-have-names@1.2.3: {} - gaxios@7.1.5(supports-color@10.2.2): + gaxios@7.1.5: dependencies: extend: 3.0.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) + https-proxy-agent: 7.0.6 node-fetch: 3.3.2 transitivePeerDependencies: - supports-color - gcp-metadata@8.1.2(supports-color@10.2.2): + gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.5(supports-color@10.2.2) + gaxios: 7.1.5 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -12225,7 +12268,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-uri@6.0.5(supports-color@10.2.2): + get-uri@6.0.5: dependencies: basic-ftp: 6.0.1 data-uri-to-buffer: 6.0.2 @@ -12293,12 +12336,12 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - google-auth-library@10.7.0(supports-color@10.2.2): + google-auth-library@10.7.0: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5(supports-color@10.2.2) - gcp-metadata: 8.1.2(supports-color@10.2.2) + gaxios: 7.1.5 + gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 jws: 4.0.1 transitivePeerDependencies: @@ -12390,29 +12433,29 @@ snapshots: http-link-header@1.1.3: {} - http-proxy-agent@7.0.2(supports-color@10.2.2): + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - http-proxy@1.18.1(debug@4.4.3(supports-color@10.2.2)): + http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2)) + follow-redirects: 1.16.0 requires-port: 1.0.0 transitivePeerDependencies: - debug - http-server@14.1.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2): + http-server@14.1.1(supports-color@10.2.2): dependencies: basic-auth: 2.0.1 chalk: 4.1.2 corser: 2.0.1 he: 1.2.0 html-encoding-sniffer: 3.0.0 - http-proxy: 1.18.1(debug@4.4.3(supports-color@10.2.2)) + http-proxy: 1.18.1 mime: 1.6.0 minimist: 1.2.8 opener: 1.5.2 @@ -12424,7 +12467,14 @@ snapshots: - debug - supports-color - https-proxy-agent@7.0.6(supports-color@10.2.2): + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@10.2.2) @@ -12695,18 +12745,18 @@ snapshots: dependencies: append-transform: 2.0.0 - istanbul-lib-instrument@4.0.3(supports-color@10.2.2): + istanbul-lib-instrument@4.0.3: dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color - istanbul-lib-instrument@6.0.3(supports-color@10.2.2): + istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/parser': 7.29.7 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 @@ -12774,10 +12824,10 @@ snapshots: jest-util: 30.4.1 p-limit: 3.1.0 - jest-circus@30.4.2(supports-color@10.2.2): + jest-circus@30.4.2: dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1(supports-color@10.2.2) + '@jest/expect': 30.4.1 '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 '@types/node': 25.9.2 @@ -12788,8 +12838,8 @@ snapshots: jest-each: 30.4.1 jest-matcher-utils: 30.4.1 jest-message-util: 30.4.1 - jest-runtime: 30.4.2(supports-color@10.2.2) - jest-snapshot: 30.4.1(supports-color@10.2.2) + jest-runtime: 30.4.2 + jest-snapshot: 30.4.1 jest-util: 30.4.1 p-limit: 3.1.0 pretty-format: 30.4.1 @@ -12800,7 +12850,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.4.2(@types/node@25.9.2)(supports-color@10.2.2): + jest-cli@30.4.2(@types/node@25.9.2): dependencies: '@jest/core': 30.4.2(supports-color@10.2.2) '@jest/test-result': 30.4.1 @@ -12808,7 +12858,7 @@ snapshots: chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) + jest-config: 30.4.2(@types/node@25.9.2) jest-util: 30.4.1 jest-validate: 30.4.1 yargs: 17.7.2 @@ -12819,25 +12869,25 @@ snapshots: - supports-color - ts-node - jest-config@30.4.2(@types/node@25.9.2)(supports-color@10.2.2): + jest-config@30.4.2(@types/node@25.9.2): dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@jest/get-type': 30.1.0 '@jest/pattern': 30.4.0 '@jest/test-sequencer': 30.4.1 '@jest/types': 30.4.1 - babel-jest: 30.4.1(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-jest: 30.4.1(@babel/core@7.29.7) chalk: 4.1.2 ci-info: 4.4.0 deepmerge: 4.3.1 glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 30.4.2(supports-color@10.2.2) + jest-circus: 30.4.2 jest-docblock: 30.4.0 jest-environment-node: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-runner: 30.4.2(supports-color@10.2.2) + jest-runner: 30.4.2 jest-util: 30.4.1 jest-validate: 30.4.1 parse-json: 5.2.0 @@ -12936,7 +12986,7 @@ snapshots: optionalDependencies: jest-resolve: 30.4.1 - jest-process-manager@0.4.0(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2): + jest-process-manager@0.4.0(supports-color@10.2.2): dependencies: '@types/wait-on': 5.3.4 chalk: 4.1.2 @@ -12947,17 +12997,17 @@ snapshots: signal-exit: 3.0.7 spawnd: 5.0.0(supports-color@10.2.2) tree-kill: 1.2.2 - wait-on: 7.2.0(debug@4.4.3(supports-color@10.2.2)) + wait-on: 7.2.0 transitivePeerDependencies: - debug - supports-color jest-regex-util@30.4.0: {} - jest-resolve-dependencies@30.4.2(supports-color@10.2.2): + jest-resolve-dependencies@30.4.2: dependencies: jest-regex-util: 30.4.0 - jest-snapshot: 30.4.1(supports-color@10.2.2) + jest-snapshot: 30.4.1 transitivePeerDependencies: - supports-color @@ -12972,12 +13022,12 @@ snapshots: slash: 3.0.0 unrs-resolver: 1.12.2 - jest-runner@30.4.2(supports-color@10.2.2): + jest-runner@30.4.2: dependencies: '@jest/console': 30.4.1 '@jest/environment': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@jest/transform': 30.4.1 '@jest/types': 30.4.1 '@types/node': 25.9.2 chalk: 4.1.2 @@ -12990,7 +13040,7 @@ snapshots: jest-leak-detector: 30.4.1 jest-message-util: 30.4.1 jest-resolve: 30.4.1 - jest-runtime: 30.4.2(supports-color@10.2.2) + jest-runtime: 30.4.2 jest-util: 30.4.1 jest-watcher: 30.4.1 jest-worker: 30.4.1 @@ -12999,14 +13049,14 @@ snapshots: transitivePeerDependencies: - supports-color - jest-runtime@30.4.2(supports-color@10.2.2): + jest-runtime@30.4.2: dependencies: '@jest/environment': 30.4.1 '@jest/fake-timers': 30.4.1 - '@jest/globals': 30.4.1(supports-color@10.2.2) + '@jest/globals': 30.4.1 '@jest/source-map': 30.0.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@jest/transform': 30.4.1 '@jest/types': 30.4.1 '@types/node': 25.9.2 chalk: 4.1.2 @@ -13019,7 +13069,7 @@ snapshots: jest-mock: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-snapshot: 30.4.1(supports-color@10.2.2) + jest-snapshot: 30.4.1 jest-util: 30.4.1 slash: 3.0.0 strip-bom: 4.0.0 @@ -13030,19 +13080,19 @@ snapshots: dependencies: diffable-html: 4.1.0 - jest-snapshot@30.4.1(supports-color@10.2.2): + jest-snapshot@30.4.1: dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 '@babel/generator': 7.29.7 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) '@babel/types': 7.29.0 '@jest/expect-utils': 30.4.1 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.4.1 - '@jest/transform': 30.4.1(supports-color@10.2.2) + '@jest/transform': 30.4.1 '@jest/types': 30.4.1 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@10.2.2)) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) chalk: 4.1.2 expect: 30.4.1 graceful-fs: 4.2.11 @@ -13074,7 +13124,7 @@ snapshots: leven: 3.1.0 pretty-format: 30.4.1 - jest-watch-typeahead@3.0.1(jest@30.4.2(@types/node@25.9.2)(supports-color@10.2.2)): + jest-watch-typeahead@3.0.1(jest@30.4.2(@types/node@25.9.2)): dependencies: ansi-escapes: 7.3.0 chalk: 5.6.2 @@ -13109,7 +13159,7 @@ snapshots: '@jest/core': 30.4.2(supports-color@10.2.2) '@jest/types': 30.4.1 import-local: 3.2.0 - jest-cli: 30.4.2(@types/node@25.9.2)(supports-color@10.2.2) + jest-cli: 30.4.2(@types/node@25.9.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13139,7 +13189,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.2.0: + js-yaml@4.3.0: dependencies: argparse: 2.0.1 @@ -13260,7 +13310,7 @@ snapshots: transitivePeerDependencies: - supports-color - lighthouse-logger@2.0.2(supports-color@10.2.2): + lighthouse-logger@2.0.2: dependencies: debug: 4.4.3(supports-color@10.2.2) marky: 1.3.0 @@ -13274,7 +13324,7 @@ snapshots: '@paulirish/trace_engine': 0.0.53 '@sentry/node': 7.120.4 axe-core: 4.11.4 - chrome-launcher: 1.2.1(supports-color@10.2.2) + chrome-launcher: 1.2.1 configstore: 5.0.1 csp_evaluator: 1.1.5 devtools-protocol: 0.0.1467305 @@ -13283,7 +13333,7 @@ snapshots: intl-messageformat: 10.7.18 jpeg-js: 0.4.4 js-library-detector: 6.7.0 - lighthouse-logger: 2.0.2(supports-color@10.2.2) + lighthouse-logger: 2.0.2 lighthouse-stack-packs: 1.12.2 lodash-es: 4.18.1 lookup-closest-locale: 6.2.0 @@ -13511,15 +13561,16 @@ snapshots: min-indent@1.0.1: {} - miniflare@4.20260609.0: + miniflare@4.20260609.0(@types/node@25.9.2): dependencies: '@cspotcode/source-map-support': 0.8.1 - sharp: 0.34.5 + sharp: 0.35.3(@types/node@25.9.2) undici: 7.28.0 workerd: 1.20260609.1 ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate @@ -13527,19 +13578,19 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimatch@3.1.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimatch@5.1.9: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimatch@9.0.9: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimist@1.2.8: {} @@ -13569,7 +13620,7 @@ snapshots: mute-stream@3.0.0: {} - nanoid@3.3.12: {} + nanoid@3.3.16: {} nanoid@5.1.11: {} @@ -13628,7 +13679,7 @@ snapshots: glob: 7.2.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 4.0.3(supports-color@10.2.2) + istanbul-lib-instrument: 4.0.3 istanbul-lib-processinfo: 2.0.3 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1(supports-color@10.2.2) @@ -13696,7 +13747,7 @@ snapshots: onnxruntime-node@1.24.3: dependencies: - adm-zip: 0.5.17 + adm-zip: 0.6.0 global-agent: 3.0.0 onnxruntime-common: 1.24.3 optional: true @@ -13830,16 +13881,16 @@ snapshots: p-try@2.2.0: {} - pac-proxy-agent@7.2.0(supports-color@10.2.2): + pac-proxy-agent@7.2.0: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 debug: 4.4.3(supports-color@10.2.2) - get-uri: 6.0.5(supports-color@10.2.2) - http-proxy-agent: 7.0.2(supports-color@10.2.2) - https-proxy-agent: 7.0.6(supports-color@10.2.2) + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5(supports-color@10.2.2) + socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color @@ -13945,9 +13996,9 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss@8.5.15: + postcss@8.5.23: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -14007,16 +14058,16 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-agent@6.5.0(supports-color@10.2.2): + proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@10.2.2) - http-proxy-agent: 7.0.2(supports-color@10.2.2) - https-proxy-agent: 7.0.6(supports-color@10.2.2) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0(supports-color@10.2.2) + pac-proxy-agent: 7.2.0 proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5(supports-color@10.2.2) + socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color @@ -14078,10 +14129,10 @@ snapshots: dependencies: typescript: 6.0.3 - react-docgen@8.0.3(supports-color@10.2.2): + react-docgen@8.0.3: dependencies: - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -14417,6 +14468,8 @@ snapshots: semver@7.8.4: {} + semver@7.8.5: {} + send@0.19.2(supports-color@10.2.2): dependencies: debug: 2.6.9(supports-color@10.2.2) @@ -14442,7 +14495,7 @@ snapshots: serialize-javascript@7.0.5: {} - serve-static@1.16.3(supports-color@10.2.2): + serve-static@1.16.3: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 @@ -14479,36 +14532,38 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.34.5: + sharp@0.35.3(@types/node@25.9.2): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.4 + semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 25.9.2 shebang-command@2.0.0: dependencies: @@ -14592,7 +14647,7 @@ snapshots: smob@1.6.2: {} - socks-proxy-agent@8.0.5(supports-color@10.2.2): + socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@10.2.2) @@ -15240,13 +15295,13 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-pwa@1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2))(workbox-window@7.4.1): + vite-plugin-pwa@1.3.0(supports-color@10.2.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1): dependencies: debug: 4.4.3(supports-color@10.2.2) pretty-bytes: 6.1.1 tinyglobby: 0.2.16 vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) - workbox-build: 7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2) + workbox-build: 7.4.1(@types/babel__core@7.20.5) workbox-window: 7.4.1 transitivePeerDependencies: - supports-color @@ -15255,7 +15310,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -15301,25 +15356,27 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - wait-on@7.2.0(debug@4.4.3(supports-color@10.2.2)): + wait-on@7.2.0: dependencies: - axios: 1.16.0(debug@4.4.3(supports-color@10.2.2)) + axios: 1.18.1 joi: 18.2.1 lodash: 4.18.1 minimist: 1.2.8 rxjs: 7.8.2 transitivePeerDependencies: - debug + - supports-color - wait-on@9.0.10(debug@4.4.3(supports-color@10.2.2)): + wait-on@9.0.10: dependencies: - axios: 1.16.0(debug@4.4.3(supports-color@10.2.2)) + axios: 1.18.1 joi: 18.2.1 lodash: 4.18.1 minimist: 1.2.8 rxjs: 7.8.2 transitivePeerDependencies: - debug + - supports-color wait-port@0.2.14(supports-color@10.2.2): dependencies: @@ -15441,13 +15498,13 @@ snapshots: dependencies: workbox-core: 7.4.1 - workbox-build@7.4.1(@types/babel__core@7.20.5)(supports-color@10.2.2): + workbox-build@7.4.1(@types/babel__core@7.20.5): dependencies: '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) - '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/core': 7.29.7 + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) '@babel/runtime': 7.29.7 - '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(@types/babel__core@7.20.5)(rollup@4.62.2)(supports-color@10.2.2) + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.2) '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.2) '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) '@rollup/plugin-terser': 1.0.0(rollup@4.62.2) @@ -15553,19 +15610,20 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260609.1 '@cloudflare/workerd-windows-64': 1.20260609.1 - wrangler@4.99.0: + wrangler@4.99.0(@types/node@25.9.2): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260609.1) blake3-wasm: 2.1.5 esbuild: 0.28.1 - miniflare: 4.20260609.0 + miniflare: 4.20260609.0(@types/node@25.9.2) path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 workerd: 1.20260609.1 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a7ada971..21442b7b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -47,19 +47,23 @@ overrides: tmp: ">=0.2.7" "@xmldom/xmldom": ">=0.8.13" protobufjs: ">=8.4.1" - axios: ">=1.15.2" + axios: ">=1.18.0" basic-ftp: ">=5.3.1" - fast-uri: ">=3.1.2" + fast-uri: ">=3.1.4 <4" ip-address: ">=10.1.1" ws: ">=8.21.0" form-data: ">=4.0.6" - brace-expansion: ">=5.0.6" + brace-expansion: ">=5.0.8" uuid: ">=11.1.1" qs: ">=6.15.2" dompurify: ">=3.4.11" "@babel/core": ">=7.29.6" undici: ">=7.28.0 <8" - js-yaml: ">=4.1.2" + js-yaml: ">=4.3.0 <5" + # QNBS-v3 (2026-07-26): GHSA batch blocking the CI security gate — transitive-only dev paths. + adm-zip: ">=0.6.0" # GHSA-xcpc-8h2w-3j85 — 4GB memory allocation via crafted ZIP (onnxruntime-node) + postcss: ">=8.5.18" # GHSA — path traversal in previous source map (vite/storybook chain) + sharp: ">=0.35.0" # inherited libvips vulnerabilities (@huggingface/transformers, miniflare) peerDependencyRules: allowedVersions: From e382bd90b8d30f02fa6e515c1bbf83a52a5ddb65 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 10:10:42 +0200 Subject: [PATCH 09/14] ci(security): retry pnpm audit on transient registry gzip failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The npm audit bulk endpoint intermittently returns an undecoded gzip body (ERR_PNPM_AUDIT_BAD_RESPONSE) — a registry/CDN-side flake, not a finding. 3 attempts with 20s backoff; real advisories still fail the gate. --- .github/workflows/ci.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e2af625..5dcfa964 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,8 +45,19 @@ jobs: fetch-depth: 0 - uses: ./.github/actions/setup + # QNBS-v3: retry wrapper — the npm audit bulk endpoint intermittently returns an undecoded + # gzip body (ERR_PNPM_AUDIT_BAD_RESPONSE) when a CDN node force-compresses the large response; + # transient registry behavior, not an audit finding. Retries land on different edge nodes. - name: pnpm audit (high + critical) - run: pnpm audit --audit-level=high + run: | + for attempt in 1 2 3; do + if pnpm audit --audit-level=high; then + exit 0 + fi + echo "::warning::pnpm audit attempt ${attempt} failed — retrying in 20s" + sleep 20 + done + exit 1 # QNBS-v3 (#60): vendored y-webrtc fork invariant guard (PBKDF2 600k, non-extractable keys, # DataChannel encryption, no dangling upstream dep) — fails the build on fork drift. From e9856232a760db660b6f5762a1cd592d41477786 Mon Sep 17 00:00:00 2001 From: qnbs <155236708+qnbs@users.noreply.github.com> Date: Sun, 26 Jul 2026 14:44:48 +0200 Subject: [PATCH 10/14] =?UTF-8?q?fix:=20address=20PR=20#269=20review=20?= =?UTF-8?q?=E2=80=94=20PWA=20button=20gating,=20CSP=20claim,=20audit=20CI?= =?UTF-8?q?=20gate,=20vendor=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AiProviderCard: disable 'Load models' + 'Test connection' for ollama in PWA - i18n: ollamaDesktopOnlyBody blames CORS/PNA, not CSP (ADR-0012) — all 19 locales + bundles - ci: pnpm audit step now advisory (continue-on-error) — registry serves force-gzipped body pnpm cannot decode (ERR_PNPM_AUDIT_BAD_RESPONSE, deterministic per CDN edge); OSV scan of both lockfiles remains the enforced gate - verify-vendor-fork: path-sensitive DataChannel encrypt/decrypt checks + full surface scan (workspace manifests, pnpm-lock, patches glob) - ollamaService.streamOllama: rethrow AbortError before wrapping (caller cancel ≠ unreachable) - collab-transport crypto.js header: SC patch naming, decrypt() fix, QNBS-v3 tag - tests: scan tests use vi.stubGlobal/unstubAllGlobals; localServerHttp header comment - docs: flag count truth 22 (16 on / 6 off) across AGENTS.md, CLAUDE.md, copilot-instructions.md, FEATURE-PARITY.md, CHANGELOG; VENDOR-FORKS.md AUDIT.md ref --- .github/copilot-instructions.md | 2 +- .github/workflows/ci.yml | 24 ++++++------ AGENTS.md | 4 +- CHANGELOG.md | 2 +- CLAUDE.md | 4 +- VENDOR-FORKS.md | 2 +- components/settings/AiProviderCard.tsx | 10 ++++- docs/FEATURE-PARITY.md | 2 +- locales/ar/settings.json | 2 +- locales/de/settings.json | 2 +- locales/el/settings.json | 2 +- locales/en/settings.json | 2 +- locales/es/settings.json | 2 +- locales/eu/settings.json | 2 +- locales/fa/settings.json | 2 +- locales/fi/settings.json | 2 +- locales/fr/settings.json | 2 +- locales/he/settings.json | 2 +- locales/hu/settings.json | 2 +- locales/is/settings.json | 2 +- locales/it/settings.json | 2 +- locales/ja/settings.json | 2 +- locales/ko/settings.json | 2 +- locales/pt/settings.json | 2 +- locales/ru/settings.json | 2 +- locales/sv/settings.json | 2 +- locales/zh/settings.json | 2 +- packages/collab-transport/src/crypto.js | 6 +-- public/locales/ar/bundle.json | 2 +- public/locales/de/bundle.json | 2 +- public/locales/el/bundle.json | 2 +- public/locales/en/bundle.json | 2 +- public/locales/es/bundle.json | 2 +- public/locales/eu/bundle.json | 2 +- public/locales/fa/bundle.json | 2 +- public/locales/fi/bundle.json | 2 +- public/locales/fr/bundle.json | 2 +- public/locales/he/bundle.json | 2 +- public/locales/hu/bundle.json | 2 +- public/locales/is/bundle.json | 2 +- public/locales/it/bundle.json | 2 +- public/locales/ja/bundle.json | 2 +- public/locales/ko/bundle.json | 2 +- public/locales/pt/bundle.json | 2 +- public/locales/ru/bundle.json | 2 +- public/locales/sv/bundle.json | 2 +- public/locales/zh/bundle.json | 2 +- scripts/verify-vendor-fork.mjs | 50 ++++++++++++++++++++++--- services/ollamaService.ts | 4 ++ tests/unit/aiProviderService.test.ts | 21 ++++++----- tests/unit/localServerHttp.test.ts | 3 ++ 51 files changed, 131 insertions(+), 79 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 91c59331..443a14ef 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -63,7 +63,7 @@ types.ts → Core shared interfaces and types 9. **Voice Full Support:** Gated behind `featureFlags.enableVoiceSupport` + `settings.voice.enabled`. Abstract engine pattern in `services/voice/voiceTypes.ts` (SttEngine, TtsEngine, VadEngine, WakeWordEngine, IntentEngine). `VoiceCommandService` singleton manages state machine (idle → listening → processing → speaking). Web Speech API fallbacks require zero downloads. Hooks: `useVoice`, `usePushToTalk` (Ctrl+Shift+V), `useVoiceDictation`. -10. **Feature Flags:** **23 flags** in `features/featureFlags/featureFlagsSlice.ts`. New installs get the **full feature set** — all default **on** except five opt-in flags that default **off**: `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md`. Do not use scattered `if (true)` hacks — all experimental features must go through a flag. +10. **Feature Flags:** **22 flags** in `features/featureFlags/featureFlagsSlice.ts`. New installs get the **full feature set** — all default **on** except six opt-in flags that default **off**: `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md`. Do not use scattered `if (true)` hacks — all experimental features must go through a flag. 11. **Global AI Copilot (v2):** `enableGlobalCopilot` flag. `CopilotPanel` (dialog/sidebar mode), `CopilotMessageList` (markdown rendering via DOMPurify), `InlineAnnotationLayer` (badge in ManuscriptEditor). Heuristic rules: `services/copilot/heuristicEngine.ts` (8 rules). Apply-to-chapter: `services/copilot/actionApplier.ts` (offset-safe edit, redux-undo, ≥70% length gate). ProForge integration: Ask-Copilot chip on each `ReviewItemCard`. Docs: `docs/COPILOT.md`, `docs/HEURISTIC-RULES.md`. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5dcfa964..08974cb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,19 +45,19 @@ jobs: fetch-depth: 0 - uses: ./.github/actions/setup - # QNBS-v3: retry wrapper — the npm audit bulk endpoint intermittently returns an undecoded - # gzip body (ERR_PNPM_AUDIT_BAD_RESPONSE) when a CDN node force-compresses the large response; - # transient registry behavior, not an audit finding. Retries land on different edge nodes. - - name: pnpm audit (high + critical) + # QNBS-v3: pnpm's audit client cannot decode force-gzipped responses from some npm CDN edge + # nodes (ERR_PNPM_AUDIT_BAD_RESPONSE, deterministic per edge — retries are useless). The + # enforced vulnerability gate in this job is the OSV scan below (covers BOTH pnpm-lock.yaml + # and Cargo.lock with a superset DB); this step is advisory-only until pnpm fixes decoding. + - name: pnpm audit (high + critical, advisory) + continue-on-error: true run: | - for attempt in 1 2 3; do - if pnpm audit --audit-level=high; then - exit 0 - fi - echo "::warning::pnpm audit attempt ${attempt} failed — retrying in 20s" - sleep 20 - done - exit 1 + if pnpm audit --audit-level=high; then + echo "pnpm audit: clean" + else + echo "::warning::pnpm audit failed (registry gzip-decoding bug or findings) — OSV scan below is the enforced gate" + exit 1 + fi # QNBS-v3 (#60): vendored y-webrtc fork invariant guard (PBKDF2 600k, non-extractable keys, # DataChannel encryption, no dangling upstream dep) — fails the build on fork drift. diff --git a/AGENTS.md b/AGENTS.md index f374c9fd..e31b362b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -84,7 +84,7 @@ WorldScript-Studio/ │ ├── status/ # App-wide status / loading flags │ ├── writer/ # Writer view state │ ├── versionControl/ # Snapshots and branches -│ ├── featureFlags/ # 23 flags — full set on by default; 5 opt-in (default-off) +│ ├── featureFlags/ # 22 flags — full set on by default; 6 opt-in (default-off) │ ├── plotBoard/ # Ephemeral viewport/draw state (NOT undo-able; localStorage) │ ├── progressTracker/ # Writing sessions, streaks, goals │ ├── sceneComments/ # Per-scene comments (EntityAdapter) @@ -387,7 +387,7 @@ Edge builds run `scripts/build-edge.mjs` which sets `DEPLOY_TARGET=edge` and pat ### Feature Flags -- `features/featureFlags/featureFlagsSlice.ts` gates **23 flags**. New installs get the **full feature set**: all default **on** except six opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix. +- `features/featureFlags/featureFlagsSlice.ts` gates **22 flags**. New installs get the **full feature set**: all default **on** except six opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix. - UI: Settings → Experimental flags. - Do not use scattered `if (true)` hacks. diff --git a/CHANGELOG.md b/CHANGELOG.md index ed93850d..f268cbaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,7 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 provider is still described as an adaptive-engine backend). Refreshed in the five Production locales. - **ProForge is now opt-in (default off).** The experimental 8-stage agentic editing pipeline (`enableProForge`) shipped on by default; it is token-heavy and carries loop risk, so it is now a - user opt-in like Voice and the Global Copilot. New installs get **17 default-on / 6 default-off** + user opt-in like Voice and the Global Copilot. New installs get **16 default-on / 6 default-off** flags. Existing users who enabled or relied on it are unaffected (the persisted value wins); everyone can still turn it on under Settings → Experimental. - **Settings → Experimental features are grouped by category** (Writing, AI, Editing Pipeline, diff --git a/CLAUDE.md b/CLAUDE.md index 529516c6..22d34899 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -246,7 +246,7 @@ Production uses **rolldown** (not esbuild/rollup); CI E2E runs `vite dev` — pr ### Feature Flags -Experimental features are gated behind `features/featureFlags/featureFlagsSlice.ts` (**23 flags**). New installs get the **full feature set**: all flags default **on** except six user-opt-in flags. `enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core behaviour (v1.20 / v1.8); `enablePlotBoardV2` and `enableCloudSync` were retired — none of those four remain in the slice. UI: Settings → Experimental flags (`FeatureFlagsSection.tsx`). Do not use scattered `if (true)` hacks. +Experimental features are gated behind `features/featureFlags/featureFlagsSlice.ts` (**22 flags**). New installs get the **full feature set**: all flags default **on** except six user-opt-in flags. `enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core behaviour (v1.20 / v1.8); `enablePlotBoardV2` and `enableCloudSync` were retired — none of those four remain in the slice. UI: Settings → Experimental flags (`FeatureFlagsSection.tsx`). Do not use scattered `if (true)` hacks. **Default on (17):** `enableStoryBibleAdvanced`, `enableBinderResearch`, `enableCompileWizard`, `enableProjectHealthScore`, `enableAppHealthPanel`, `enableDuckDbAnalytics`, `enableObjectsGroups`, `enableMindMaps`, `enableCharacterInterviews`, `enableLoraAdapters`, `enablePluginSystem`, `enableIdbAtRestEncryption` (B-1, passphrase UX complete — Settings › Privacy), `enableAdaptiveAiEngine`, `enableWebnnInference`, `enableComputeShaders`, `enableWorkerBusV2`, `enableRustCompute`. **User opt-in — default off (6):** `enableProForge` (experimental, token-heavy 8-stage agentic pipeline — flipped to opt-in in v1.24 post-release), `enableVoiceSupport` (requires browser mic permission), `enableVoiceWasm` (B-2, ~57 MB Whisper download), `enableGlobalCopilot` (ambient AI), `enableRtlLayout` (B-5, ar/he stubs only), `enableLocalFirstSync` (shadow Yjs projection, ADR-0008; Redux stays SoT). The Settings UI groups these by catalog tier; `features/featureCatalog.ts` **derives** each flag's `defaultOn` from the slice (no hand-keyed drift). Note: `enableCloudSync` was **retired** in v1.20 (no UI shipped; `CloudSyncBackend.create()` requires explicit-consent boolean instead). @@ -337,7 +337,7 @@ All `.md` guides listed in **[`README.md`](README.md#-documentation-hub) § Docu **useAppSelectorShallow with plotBoard:** Include `plotBoard: { activeMode: 'swimlane', snapToGrid: false, selectedConnectionId: null, isDrawingConnection: false, drawFromSectionId: null, activeSubplotFilter: null, zoom: 1, panX: 0, panY: 0 }` in mock state. Connections/subplots/tensionOverrides are in `project.present.data`. Add `// biome-ignore lint/suspicious/noExplicitAny: test mock` before `(selector: (s: any) => unknown)` lines. -**FeatureFlagsState mocks:** Always include ALL 23 flags (TypeScript strict rejects partial). Only **six** default **off**: `enableProForge`, `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync` — every other flag (including all edge-AI flags and `enableIdbAtRestEncryption`) defaults **on**. When a test needs a non-default flag state, set it explicitly in the mock — don't assume the default. +**FeatureFlagsState mocks:** Always include ALL 22 flags (TypeScript strict rejects partial). Only **six** default **off**: `enableProForge`, `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync` — every other flag (including all edge-AI flags and `enableIdbAtRestEncryption`) defaults **on**. When a test needs a non-default flag state, set it explicitly in the mock — don't assume the default. **ConnectionLayer test IDs:** `data-testid="connection-group"` — query by testid, not role. diff --git a/VENDOR-FORKS.md b/VENDOR-FORKS.md index 4108408b..0b2572ee 100644 --- a/VENDOR-FORKS.md +++ b/VENDOR-FORKS.md @@ -59,7 +59,7 @@ see advisories against it. Therefore, on every fork-maintenance review (and at m and the project's release notes — for anything at or below our base `10.3.0`. 2. If a relevant advisory exists, port the upstream fix into the vendored `src/` alongside the three encryption patches, run the `packages/collab-transport` test suite + `pnpm run verify:vendor`, - bump the `-scN` suffix, and record it in `VENDOR-DIFF.md`. + bump the `-scN` suffix, and record it in `packages/collab-transport/AUDIT.md`. 3. The fork's npm dependencies need no manual step — rely on the OSV `pnpm-lock.yaml` scan + Dependabot. > Coverage policy for unit tests lives in [`docs/COVERAGE-POLICY.md`](docs/COVERAGE-POLICY.md). diff --git a/components/settings/AiProviderCard.tsx b/components/settings/AiProviderCard.tsx index f587a21a..dc91c822 100644 --- a/components/settings/AiProviderCard.tsx +++ b/components/settings/AiProviderCard.tsx @@ -358,7 +358,7 @@ export const AiProviderCard: FC = ({ />