diff --git a/.github/actions/install-node-dependencies/action.yml b/.github/actions/install-node-dependencies/action.yml index 8b7801881eb..f06f0ffa8d8 100644 --- a/.github/actions/install-node-dependencies/action.yml +++ b/.github/actions/install-node-dependencies/action.yml @@ -28,10 +28,9 @@ runs: steps: # setup-node needs pnpm on PATH to locate and restore its store. - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js id: default-node @@ -88,7 +87,7 @@ runs: pnpm install --frozen-lockfile --ignore-scripts # Job containers can run composite steps from a source mirror without .git. if [ "$(git -C "$GITHUB_WORKSPACE" rev-parse --is-inside-work-tree 2>/dev/null)" = true ]; then - git -C "$GITHUB_WORKSPACE" diff --exit-code -- package.json pnpm-lock.yaml + git -C "$GITHUB_WORKSPACE" diff --exit-code -- package.json pnpm-lock.yaml pnpm-workspace.yaml fi # Why cached: `--ignore-scripts` leaves node-pty without build/Release, so diff --git a/.github/workflows/adhoc-mac-build.yml b/.github/workflows/adhoc-mac-build.yml index 552444046ce..59d705bf67e 100644 --- a/.github/workflows/adhoc-mac-build.yml +++ b/.github/workflows/adhoc-mac-build.yml @@ -171,10 +171,9 @@ jobs: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/daemon-relocation-spike.yml b/.github/workflows/daemon-relocation-spike.yml index 161c4894138..2ffd4a58661 100644 --- a/.github/workflows/daemon-relocation-spike.yml +++ b/.github/workflows/daemon-relocation-spike.yml @@ -43,10 +43,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/daily-mac-build.yml b/.github/workflows/daily-mac-build.yml index b439b7caad4..45130e932d8 100644 --- a/.github/workflows/daily-mac-build.yml +++ b/.github/workflows/daily-mac-build.yml @@ -145,10 +145,9 @@ jobs: - name: Setup pnpm if: steps.freshness.outputs.should_build == 'true' - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js if: steps.freshness.outputs.should_build == 'true' diff --git a/.github/workflows/dev-channel-win-build.yml b/.github/workflows/dev-channel-win-build.yml index 35abbf1c495..e16a50f1c3c 100644 --- a/.github/workflows/dev-channel-win-build.yml +++ b/.github/workflows/dev-channel-win-build.yml @@ -191,10 +191,9 @@ jobs: # pnpm must be on PATH before setup-node so setup-node can locate the store. - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 92e33a18d19..c23aa0cb679 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -55,9 +55,13 @@ jobs: env: VITE_EXPOSE_STORE: 'true' run: | - npx electron-vite build --mode e2e - pnpm run build:web-from-renderer - pnpm run build:relay + status=0 + pnpm run build:relay & + relay_pid=$! + npx electron-vite build --mode e2e || status=1 + pnpm run build:web-from-renderer || status=1 + wait "$relay_pid" || status=1 + exit "$status" - name: Upload E2E build output uses: actions/upload-artifact@v7 @@ -71,9 +75,29 @@ jobs: retention-days: 1 if-no-files-found: error + # Build Electron-native dependencies once per workflow. Consumer shards restore + # this immutable cache instead of compiling the same ABI concurrently. + prepare-native-cache: + name: prepare Electron native cache + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install native build tools + run: sudo apt-get update && sudo apt-get install -y build-essential python3 + + - uses: ./.github/actions/install-node-dependencies + with: + native-runtime: electron + e2e: name: e2e ${{ matrix.shard_name }} - needs: build + needs: [build, prepare-native-cache] if: inputs.test_files == '' runs-on: ubuntu-latest timeout-minutes: 30 @@ -159,7 +183,7 @@ jobs: changed-e2e: name: changed e2e specs - needs: build + needs: [build, prepare-native-cache] if: inputs.test_files != '' runs-on: ubuntu-latest # Why 45: pr.yml now maps SSH source edits onto Docker-backed specs, so this lane can @@ -227,8 +251,7 @@ jobs: ssh-docker-watcher-isolation: name: ssh docker watcher isolation - needs: build - # Why ssh_source_changed first: this lane used to trigger on SSH source only as a side + needs: [build, prepare-native-cache] # effect of one route listing a startup-readiness spec — pruning that spec would have # silently retired the whole lane. The signal is now derived from the SSH routes directly. # The two spec clauses stay for their honest purpose: changed-e2e hands these specs to this diff --git a/.github/workflows/golden-e2e-experiment.yml b/.github/workflows/golden-e2e-experiment.yml index 3216fb66a72..d46c80033fa 100644 --- a/.github/workflows/golden-e2e-experiment.yml +++ b/.github/workflows/golden-e2e-experiment.yml @@ -43,10 +43,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: Linux golden E2E uses the same native install path as PR/release CI, # which needs pnpm to bypass its non-executable bundled gyp_main.py. diff --git a/.github/workflows/hourly-mac-build.yml b/.github/workflows/hourly-mac-build.yml index d4dc4d3e391..ac3af92a3bc 100644 --- a/.github/workflows/hourly-mac-build.yml +++ b/.github/workflows/hourly-mac-build.yml @@ -135,10 +135,9 @@ jobs: - name: Setup pnpm if: steps.freshness.outputs.should_build == 'true' - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js if: steps.freshness.outputs.should_build == 'true' diff --git a/.github/workflows/linux-wayland-gpu-sandbox.yml b/.github/workflows/linux-wayland-gpu-sandbox.yml index 96256d5193c..15af59da8a5 100644 --- a/.github/workflows/linux-wayland-gpu-sandbox.yml +++ b/.github/workflows/linux-wayland-gpu-sandbox.yml @@ -24,10 +24,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: mirrors pr.yml so native module rebuilds do not use pnpm's # non-executable bundled gyp_main.py on Linux runners. @@ -44,12 +43,9 @@ jobs: fi - name: Install dependencies - # Why: pnpm 10.24's frozen headless fast path can fail on fresh Ubuntu - # runners while creating the root node_modules. Use the normal resolver - # path, then verify package metadata stayed unchanged. run: | - pnpm install --no-frozen-lockfile --prefer-frozen-lockfile=false - git diff --exit-code package.json pnpm-lock.yaml + pnpm install --frozen-lockfile + git diff --exit-code package.json pnpm-lock.yaml pnpm-workspace.yaml - name: Start Weston run: | diff --git a/.github/workflows/mobile-android-release.yml b/.github/workflows/mobile-android-release.yml index 6dfc99b8273..35e900dc31c 100644 --- a/.github/workflows/mobile-android-release.yml +++ b/.github/workflows/mobile-android-release.yml @@ -44,10 +44,9 @@ jobs: node-version: 24 - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/mobile-ios-release.yml b/.github/workflows/mobile-ios-release.yml index 31fe546fbf0..934b3f694a3 100644 --- a/.github/workflows/mobile-ios-release.yml +++ b/.github/workflows/mobile-ios-release.yml @@ -64,10 +64,9 @@ jobs: node-version: 24 - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index ce968e54fab..59f6cf20bf4 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -51,10 +51,9 @@ jobs: working-directory: mobile - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: the mobile typecheck imports shared types from ../src/shared, and # some of those files import runtime deps (tweetnacl, ws) resolved from diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml index 1d65ad89a21..f4db35bc314 100644 --- a/.github/workflows/release-cut.yml +++ b/.github/workflows/release-cut.yml @@ -864,10 +864,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: Linux terminal golden E2E uses the same native install path as # release CI, which needs pnpm to bypass its non-executable gyp_main.py. @@ -1080,10 +1079,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: keep the non-blocking evidence lane on the same Linux native # install path as the blocking golden and release build jobs. @@ -1195,10 +1193,9 @@ jobs: # pnpm must be on PATH before setup-node so setup-node can locate the store for caching. - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/release-mac-build.yml b/.github/workflows/release-mac-build.yml index 54fbc65d9c8..f97ac0e5537 100644 --- a/.github/workflows/release-mac-build.yml +++ b/.github/workflows/release-mac-build.yml @@ -38,10 +38,9 @@ jobs: ref: refs/tags/${{ inputs.tag }} - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/terminal-ime-e2e.yml b/.github/workflows/terminal-ime-e2e.yml index 5cf83589b02..83f5b839828 100644 --- a/.github/workflows/terminal-ime-e2e.yml +++ b/.github/workflows/terminal-ime-e2e.yml @@ -41,10 +41,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Use external node-gyp to avoid pnpm bundled copy run: | diff --git a/.github/workflows/terminal-perf.yml b/.github/workflows/terminal-perf.yml index 6c3866a8ea0..38d0a25bbb7 100644 --- a/.github/workflows/terminal-perf.yml +++ b/.github/workflows/terminal-perf.yml @@ -73,10 +73,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: this scheduled/manual workflow uses the same native install path as # PR and E2E CI, which needs pnpm to bypass its bundled gyp_main.py. diff --git a/.github/workflows/win-crash-survival-e2e.yml b/.github/workflows/win-crash-survival-e2e.yml index 13fae0c4126..f3d22cc1227 100644 --- a/.github/workflows/win-crash-survival-e2e.yml +++ b/.github/workflows/win-crash-survival-e2e.yml @@ -46,10 +46,9 @@ jobs: # Why: setup-node can restore pnpm's content-addressed store only after # the pnpm binary exists, avoiding repeat dependency downloads per run. - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/win-update-e2e.yml b/.github/workflows/win-update-e2e.yml index 604ccd92b14..2a1bde70924 100644 --- a/.github/workflows/win-update-e2e.yml +++ b/.github/workflows/win-update-e2e.yml @@ -85,10 +85,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false # Why: the harness only needs its runtime deps (the Playwright Electron # driver); it drives already-built installer artifacts, so no app build. diff --git a/.github/workflows/win-update-survival-e2e.yml b/.github/workflows/win-update-survival-e2e.yml index f3d3c21bff7..e7ed41125e9 100644 --- a/.github/workflows/win-update-survival-e2e.yml +++ b/.github/workflows/win-update-survival-e2e.yml @@ -58,10 +58,9 @@ jobs: node-version-file: package.json - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/windows-signing-rehearsal.yml b/.github/workflows/windows-signing-rehearsal.yml index 18aadd7d933..54b751908dc 100644 --- a/.github/workflows/windows-signing-rehearsal.yml +++ b/.github/workflows/windows-signing-rehearsal.yml @@ -46,10 +46,9 @@ jobs: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.github/workflows/windows-terminal-restart-e2e.yml b/.github/workflows/windows-terminal-restart-e2e.yml index 3a5b4a35715..abb8dc89aa8 100644 --- a/.github/workflows/windows-terminal-restart-e2e.yml +++ b/.github/workflows/windows-terminal-restart-e2e.yml @@ -32,10 +32,9 @@ jobs: # Why: pnpm must exist before setup-node resolves its dependency cache. - name: Setup pnpm - uses: pnpm/action-setup@v6 + uses: pnpm/setup@v2 with: - version: 10.24.0 - run_install: false + install: false - name: Setup Node.js uses: actions/setup-node@v6 diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 313e39e8526..00000000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -shamefully-hoist=true -minimum-release-age=4320 diff --git a/.oxlintrc.json b/.oxlintrc.json index 97a2b68701a..e0c03a3b045 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -40,6 +40,18 @@ "react/no-string-refs": "error", "react/no-unescaped-entities": "error", "react/require-render-return": "error", + "react/error-boundaries": "error", + "react/globals": "error", + "react/immutability": "off", + "react/incompatible-library": "off", + "react/preserve-manual-memoization": "off", + "react/purity": "off", + "react/refs": "off", + "react/set-state-in-effect": "off", + "react/set-state-in-render": "error", + "react/static-components": "off", + "react/use-memo": "error", + "react/void-use-memo": "error", "react/jsx-curly-brace-presence": [ "error", { "props": "never", "children": "never", "propElementValues": "always" } @@ -62,6 +74,7 @@ "typescript/consistent-type-definitions": ["error", "type"], "typescript/consistent-type-imports": "error", "typescript/no-explicit-any": ["error", { "ignoreRestArgs": true }], + "typescript/no-confusing-non-null-assertion": "error", "typescript/no-import-type-side-effects": "error", "typescript/no-unnecessary-boolean-literal-compare": "error", "typescript/no-unnecessary-template-expression": "error", @@ -131,6 +144,7 @@ { "files": ["**/*.test.*", "**/*.spec.*", "**/*-benchmark.*"], "rules": { + "react/globals": "off", "quadratic-buffer-concat/no-loop-carried-concat": "off", "renderer-scrollbar-style/require-styled-vertical-scrollbar": "off" } diff --git a/config/docker/headless-pairing/Dockerfile.build b/config/docker/headless-pairing/Dockerfile.build index 900607a7a5c..19f76290c75 100644 --- a/config/docker/headless-pairing/Dockerfile.build +++ b/config/docker/headless-pairing/Dockerfile.build @@ -26,6 +26,7 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* RUN corepack enable \ - && corepack prepare pnpm@10.24.0 --activate + && corepack prepare pnpm@12.0.0 --activate \ + && pnpm --version WORKDIR /workspace diff --git a/config/max-lines-baseline.txt b/config/max-lines-baseline.txt index 75e536a2198..1ec04ed59ba 100644 --- a/config/max-lines-baseline.txt +++ b/config/max-lines-baseline.txt @@ -3,72 +3,40 @@ # split the oversized file instead (AGENTS.md → "Do Not Disable Max Lines"). # Regenerate/prune: pnpm check:max-lines-ratchet --prune (removes stale entries only) inline src/main/agent-hooks/server.ts -inline src/main/automations/external-manager.ts inline src/main/browser/agent-browser-bridge.ts inline src/main/browser/browser-cookie-import.ts inline src/main/browser/browser-manager.ts -inline src/main/browser/cdp-bridge.ts -inline src/main/claude-accounts/runtime-auth-service.ts inline src/main/codex-accounts/runtime-home-service.ts -inline src/main/codex-accounts/service.ts -inline src/main/codex/hook-service.ts -inline src/main/daemon/daemon-init.ts -inline src/main/git/worktree.ts -inline src/main/github/project-view.ts inline src/main/index.ts -inline src/main/ipc/filesystem-watcher.ts inline src/main/ipc/filesystem.ts inline src/main/ipc/worktree-remote.ts -inline src/main/providers/local-pty-provider.ts inline src/main/rate-limits/service.ts inline src/main/runtime/orca-runtime-browser.ts inline src/main/runtime/orca-runtime-files.ts inline src/main/runtime/orca-runtime.test.ts inline src/main/runtime/orca-runtime.ts inline src/main/runtime/rpc/methods/orchestration.ts -inline src/main/runtime/runtime-rpc.ts -inline src/main/source-control/hosted-review-creation.ts -inline src/main/speech/stt-service.ts inline src/main/ssh/ssh-channel-multiplexer.ts inline src/main/ssh/ssh-connection.ts inline src/main/ssh/ssh-relay-deploy.ts inline src/main/ssh/ssh-relay-session.ts inline src/main/updater.ts -inline src/main/window/attach-main-window-services.ts inline src/preload/index.ts -inline src/relay/dispatcher.ts -inline src/relay/git-handler.ts inline src/relay/pty-handler.ts -inline src/relay/workspace-space-scan.ts -inline src/renderer/src/components/GitLabItemDialog.tsx -inline src/renderer/src/components/LinearItemDrawer.tsx inline src/renderer/src/components/TaskPage.tsx inline src/renderer/src/components/Terminal.tsx inline src/renderer/src/components/WorktreeJumpPalette.tsx -inline src/renderer/src/components/activity/ActivityPrototypePage.tsx inline src/renderer/src/components/automations/AutomationsPage.tsx inline src/renderer/src/components/editor/CombinedDiffViewer.tsx inline src/renderer/src/components/editor/MarkdownPreview.tsx inline src/renderer/src/components/floating-terminal/FloatingTerminalPanel.tsx inline src/renderer/src/components/new-workspace/SmartWorkspaceNameField.tsx -inline src/renderer/src/components/right-sidebar/PortsPanel.tsx -inline src/renderer/src/components/settings/AccountsPane.tsx -inline src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx -inline src/renderer/src/components/settings/Settings.tsx -inline src/renderer/src/components/status-bar/ResourceUsageStatusSegment.tsx inline src/renderer/src/components/status-bar/StatusBar.tsx inline src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx inline src/renderer/src/components/terminal-pane/TerminalPane.tsx inline src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.ts inline src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts -inline src/renderer/src/hooks/useAutomationDispatchEvents.ts -inline src/renderer/src/hooks/useSettingsNavigationMetadata.ts -inline src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts -inline src/renderer/src/lib/pane-manager/pane-tree-ops.ts -inline src/renderer/src/runtime/remote-runtime-terminal-multiplexer.ts -inline src/renderer/src/runtime/runtime-file-client.ts inline src/renderer/src/runtime/sync-runtime-graph.ts -inline src/renderer/src/runtime/web-runtime-session.ts inline src/renderer/src/runtime/web-session-tabs-sync.ts inline src/renderer/src/store/slices/agent-status.ts inline src/renderer/src/store/slices/browser.ts @@ -76,16 +44,11 @@ inline src/renderer/src/store/slices/linear.ts inline src/renderer/src/store/slices/tabs.ts inline src/renderer/src/store/slices/ui.ts inline src/shared/keybindings.ts -inline src/shared/telemetry-events.ts mobile-config app/h/*/files/*.tsx -mobile-config app/h/*/index.tsx mobile-config app/h/*/session/*.tsx mobile-config app/h/*/source-control/*.tsx mobile-config app/h/*/tasks.tsx mobile-config app/index.tsx -mobile-config app/troubleshoot.tsx mobile-config scripts/mock-server.ts -mobile-config src/browser/MobileBrowserPane.tsx -mobile-config src/components/NewWorktreeModal.tsx mobile-config src/terminal/terminal-webview-html.ts mobile-config src/transport/rpc-client.ts diff --git a/config/patches/@vscode__windows-process-tree@0.8.0.patch b/config/patches/@vscode__windows-process-tree@0.8.0.patch index 65cf2be5ce4..10780f5288a 100644 --- a/config/patches/@vscode__windows-process-tree@0.8.0.patch +++ b/config/patches/@vscode__windows-process-tree@0.8.0.patch @@ -10,7 +10,7 @@ index 855bd4b86f0a3c18c7594212c0e42b6e35bc4001..33774e7ae296f0de39dd94156673c9e7 ], "conditions": [ ['OS=="win"', { -@@ -15,14 +14,13 @@ +@@ -15,12 +14,11 @@ "src/process_commandline.cc" ], - "include_dirs": [], diff --git a/config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch b/config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch index dece243837f..de8de45664f 100644 --- a/config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch +++ b/config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch @@ -1,4 +1,4 @@ -diff -ruN a/lib/addon-webgl.js b/lib/addon-webgl.js +diff --git a/lib/addon-webgl.js b/lib/addon-webgl.js --- a/lib/addon-webgl.js +++ b/lib/addon-webgl.js @@ -1,2 +1,15 @@ @@ -20,7 +20,7 @@ diff -ruN a/lib/addon-webgl.js b/lib/addon-webgl.js + outColor = texture(u_texture[0], v_texcoord); + } ${e4} else { outColor = vec4(0.0, 0.0, 0.0, 0.0); } +}`})(s2.TextureAtlas.maxAtlasPages),this._logService)),this._register((0,a.toDisposable)(()=>h2.deleteProgram(this._program))),this._projectionLocation=(0,n.throwIfFalsy)(h2.getUniformLocation(this._program,"u_projection")),this._resolutionLocation=(0,n.throwIfFalsy)(h2.getUniformLocation(this._program,"u_resolution")),this._textureLocation=(0,n.throwIfFalsy)(h2.getUniformLocation(this._program,"u_texture"));const T2=this._vertexArrayObject=h2.createVertexArray();this._register((0,a.toDisposable)(()=>h2.deleteVertexArray(T2))),h2.bindVertexArray(T2);const l2=new Float32Array([0,0,1,0,0,1,1,1]),d2=h2.createBuffer();this._register((0,a.toDisposable)(()=>h2.deleteBuffer(d2))),h2.bindBuffer(h2.ARRAY_BUFFER,d2),h2.bufferData(h2.ARRAY_BUFFER,l2,h2.STATIC_DRAW),h2.enableVertexAttribArray(0),h2.vertexAttribPointer(0,2,this._gl.FLOAT,false,0,0);const c=new Uint8Array([0,1,2,3]),_=h2.createBuffer();this._register((0,a.toDisposable)(()=>h2.deleteBuffer(_))),h2.bindBuffer(h2.ELEMENT_ARRAY_BUFFER,_),h2.bufferData(h2.ELEMENT_ARRAY_BUFFER,c,h2.STATIC_DRAW),this._attributesBuffer=(0,n.throwIfFalsy)(h2.createBuffer()),this._register((0,a.toDisposable)(()=>h2.deleteBuffer(this._attributesBuffer))),h2.bindBuffer(h2.ARRAY_BUFFER,this._attributesBuffer),h2.enableVertexAttribArray(2),h2.vertexAttribPointer(2,2,h2.FLOAT,false,44,0),h2.vertexAttribDivisor(2,1),h2.enableVertexAttribArray(3),h2.vertexAttribPointer(3,2,h2.FLOAT,false,44,2*Float32Array.BYTES_PER_ELEMENT),h2.vertexAttribDivisor(3,1),h2.enableVertexAttribArray(4),h2.vertexAttribPointer(4,1,h2.FLOAT,false,44,4*Float32Array.BYTES_PER_ELEMENT),h2.vertexAttribDivisor(4,1),h2.enableVertexAttribArray(5),h2.vertexAttribPointer(5,2,h2.FLOAT,false,44,5*Float32Array.BYTES_PER_ELEMENT),h2.vertexAttribDivisor(5,1),h2.enableVertexAttribArray(6),h2.vertexAttribPointer(6,2,h2.FLOAT,false,44,7*Float32Array.BYTES_PER_ELEMENT),h2.vertexAttribDivisor(6,1),h2.enableVertexAttribArray(1),h2.vertexAttribPointer(1,2,h2.FLOAT,false,44,9*Float32Array.BYTES_PER_ELEMENT),h2.vertexAttribDivisor(1,1),h2.useProgram(this._program);const Q=new Int32Array(s2.TextureAtlas.maxAtlasPages);for(let t4=0;t4h2.deleteTexture(e4.texture))),h2.activeTexture(h2.TEXTURE0+t4),h2.bindTexture(h2.TEXTURE_2D,e4.texture),h2.texParameteri(h2.TEXTURE_2D,h2.TEXTURE_WRAP_S,h2.CLAMP_TO_EDGE),h2.texParameteri(h2.TEXTURE_2D,h2.TEXTURE_WRAP_T,h2.CLAMP_TO_EDGE),h2.texImage2D(h2.TEXTURE_2D,0,h2.RGBA,1,1,0,h2.RGBA,h2.UNSIGNED_BYTE,new Uint8Array([255,0,0,255])),this._atlasTextures[t4]=e4};h2.enable(h2.BLEND),h2.blendFunc(h2.SRC_ALPHA,h2.ONE_MINUS_SRC_ALPHA),this.handleResize()}beginFrame(){if(!this._atlas)return true;const _g=this._atlas._clearModelGeneration||0;return this._lastSeenClearModelGeneration!==_g&&(this._lastSeenClearModelGeneration=_g,true)}updateCell(t3,e3,i3,s3,r2,a2,o2,n2,L2){this._updateCell(this._vertices.attributes,t3,e3,i3,s3,r2,a2,o2,n2,L2)}_updateCell(t3,e3,i3,s3,a2,o2,d2,c,_,Q){;h=11*(i3*this._terminal.cols+e3),s3!==r.NULL_CELL_CODE&&void 0!==s3?this._atlas&&(L=c&&c.length>1?this._atlas.getRasterizedGlyphCombinedChar(c,a2,o2,d2,false,this._terminal.element):this._atlas.getRasterizedGlyph(s3,a2,o2,d2,false,this._terminal.element),T=Math.floor((this._dimensions.device.cell.width-this._dimensions.device.char.width)/2),a2!==Q&&L.offset.x>T?(l=L.offset.x-T,t3[h]=-(L.offset.x-l)+this._dimensions.device.char.left,t3[h+1]=-L.offset.y+this._dimensions.device.char.top,t3[h+2]=(L.size.x-l)/this._dimensions.device.canvas.width,t3[h+3]=L.size.y/this._dimensions.device.canvas.height,t3[h+4]=L.texturePage,t3[h+5]=L.texturePositionClipSpace.x+l/this._atlas.pages[L.texturePage].canvas.width,t3[h+6]=L.texturePositionClipSpace.y,t3[h+7]=L.sizeClipSpace.x-l/this._atlas.pages[L.texturePage].canvas.width,t3[h+8]=L.sizeClipSpace.y):(t3[h]=-L.offset.x+this._dimensions.device.char.left,t3[h+1]=-L.offset.y+this._dimensions.device.char.top,t3[h+2]=L.size.x/this._dimensions.device.canvas.width,t3[h+3]=L.size.y/this._dimensions.device.canvas.height,t3[h+4]=L.texturePage,t3[h+5]=L.texturePositionClipSpace.x,t3[h+6]=L.texturePositionClipSpace.y,t3[h+7]=L.sizeClipSpace.x,t3[h+8]=L.sizeClipSpace.y),this._optionsService.rawOptions.rescaleOverlappingGlyphs&&(0,n.allowRescaling)(s3,_,L.size.x,this._dimensions.device.cell.width)&&(t3[h+2]=(this._dimensions.device.cell.width-1)/this._dimensions.device.canvas.width)):t3.fill(0,h,h+11-1-2)}clear(){const t3=this._terminal,e3=t3.cols*t3.rows*11;this._vertices.count!==e3?this._vertices.attributes=new Float32Array(e3):this._vertices.attributes.fill(0);let i3=0;for(;i3this._atlasTextures.length&&!this._pageOverflowWarned&&(this._pageOverflowWarned=true,console.warn("xterm webgl: atlas page count ("+this._atlas.pages.length+") exceeds the renderer texture capacity ("+this._atlasTextures.length+"), some glyphs will not render correctly"));for(let t4=0;t4T2.deleteProgram(this._program))),this._projectionLocation=(0,a.throwIfFalsy)(T2.getUniformLocation(this._program,"u_projection"));const l2=this._vertexArrayObject=T2.createVertexArray();this._register((0,s2.toDisposable)(()=>T2.deleteVertexArray(l2))),T2.bindVertexArray(l2);const d2=new Float32Array([0,0,1,0,0,1,1,1]),c2=T2.createBuffer();this._register((0,s2.toDisposable)(()=>T2.deleteBuffer(c2))),T2.bindBuffer(T2.ARRAY_BUFFER,c2),T2.bufferData(T2.ARRAY_BUFFER,d2,T2.STATIC_DRAW),T2.enableVertexAttribArray(3),T2.vertexAttribPointer(3,2,this._gl.FLOAT,false,0,0);const _2=new Uint8Array([0,1,2,3]),Q2=T2.createBuffer();this._register((0,s2.toDisposable)(()=>T2.deleteBuffer(Q2))),T2.bindBuffer(T2.ELEMENT_ARRAY_BUFFER,Q2),T2.bufferData(T2.ELEMENT_ARRAY_BUFFER,_2,T2.STATIC_DRAW),this._attributesBuffer=(0,a.throwIfFalsy)(T2.createBuffer()),this._register((0,s2.toDisposable)(()=>T2.deleteBuffer(this._attributesBuffer))),T2.bindBuffer(T2.ARRAY_BUFFER,this._attributesBuffer),T2.enableVertexAttribArray(0),T2.vertexAttribPointer(0,2,T2.FLOAT,false,o,0),T2.vertexAttribDivisor(0,1),T2.enableVertexAttribArray(1),T2.vertexAttribPointer(1,2,T2.FLOAT,false,o,2*Float32Array.BYTES_PER_ELEMENT),T2.vertexAttribDivisor(1,1),T2.enableVertexAttribArray(2),T2.vertexAttribPointer(2,4,T2.FLOAT,false,o,4*Float32Array.BYTES_PER_ELEMENT),T2.vertexAttribDivisor(2,1),this._updateCachedColors(L2.colors),this._register(this._themeService.onChangeColors(t4=>{;this._updateCachedColors(t4),this._updateViewportRectangle()}))}renderBackgrounds(){this._renderVertices(this._vertices)}renderCursor(){this._renderVertices(this._verticesCursor)}_renderVertices(t3){const e3=this._gl;e3.useProgram(this._program),e3.bindVertexArray(this._vertexArrayObject),e3.uniformMatrix4fv(this._projectionLocation,false,r.PROJECTION_MATRIX),e3.bindBuffer(e3.ARRAY_BUFFER,this._attributesBuffer),e3.bufferData(e3.ARRAY_BUFFER,t3.attributes,e3.DYNAMIC_DRAW),e3.drawElementsInstanced(this._gl.TRIANGLE_STRIP,4,e3.UNSIGNED_BYTE,0,t3.count)}handleResize(){this._updateViewportRectangle()}setDimensions(t3){this._dimensions=t3}_updateCachedColors(t3){;this._bgFloat=this._colorToFloat32Array(t3.background),this._cursorFloat=this._colorToFloat32Array(t3.cursor)}_updateViewportRectangle(){this._addRectangleFloat(this._vertices.attributes,0,0,0,this._terminal.cols*this._dimensions.device.cell.width,this._terminal.rows*this._dimensions.device.cell.height,this._bgFloat)}updateBackgrounds(t3){const e3=this._terminal,i3=this._vertices;let s3,r2,a2,o2,n2,L2,h2,T2,l2,d2,c2,_2=1;for(s3=0;s3>24&255)/255,d=(L>>16&255)/255,c=(L>>8&255)/255,_=1,this._addRectangle(t3.attributes,e3,h,T,(o2-a2)*this._dimensions.device.cell.width,this._dimensions.device.cell.height,l,d,c,_)}_addRectangle(t3,e3,i3,s3,r2,a2,o2,n2,L2,h2){;t3[e3]=i3/this._dimensions.device.canvas.width,t3[e3+1]=s3/this._dimensions.device.canvas.height,t3[e3+2]=r2/this._dimensions.device.canvas.width,t3[e3+3]=a2/this._dimensions.device.canvas.height,t3[e3+4]=o2,t3[e3+5]=n2,t3[e3+6]=L2,t3[e3+7]=h2}_addRectangleFloat(t3,e3,i3,s3,r2,a2,o2){;t3[e3]=i3/this._dimensions.device.canvas.width,t3[e3+1]=s3/this._dimensions.device.canvas.height,t3[e3+2]=r2/this._dimensions.device.canvas.width,t3[e3+3]=a2/this._dimensions.device.canvas.height,t3[e3+4]=o2[0],t3[e3+5]=o2[1],t3[e3+6]=o2[2],t3[e3+7]=o2[3]}_colorToFloat32Array(t3){return new Float32Array([(t3.rgba>>24&255)/255,(t3.rgba>>16&255)/255,(t3.rgba>>8&255)/255,(255&t3.rgba)/255])}}e2.RectangleRenderer=Q},208(t2,e2,i2){;Object.defineProperty(e2,"__esModule",{value:true}),e2.RenderModel=e2.COMBINED_CHAR_BIT_MASK=void 0;const s2=i2(948);e2.COMBINED_CHAR_BIT_MASK=2147483648,e2.RenderModel=class{constructor(){;this.cells=new Uint32Array(0),this.lineLengths=new Uint32Array(0),this.selection=(0,s2.createSelectionRenderModel)()}resize(t3,e3){const i3=t3*e3*4;i3!==this.cells.length&&(this.cells=new Uint32Array(i3),this.lineLengths=new Uint32Array(e3))}clear(){;this.cells.fill(0,0),this.lineLengths.fill(0,0)}}},115(t2,e2,i2){;Object.defineProperty(e2,"__esModule",{value:true}),e2.TextureAtlas=void 0;const s2=i2(0),r=i2(183),a=i2(959),o=i2(993),n=i2(836),L=i2(930),h=i2(917),T=i2(564),l=i2(414),d={texturePage:0,texturePosition:{x:0,y:0},texturePositionClipSpace:{x:0,y:0},offset:{x:0,y:0},size:{x:0,y:0},sizeClipSpace:{x:0,y:0}};let c;class _{get pages(){return this._pages}constructor(t3,e3,i3,s3){;this._document=t3,this._config=e3,this._unicodeService=i3,this._logService=s3,this._didWarmUp=false,this._cacheMap=new n.FourKeyMap,this._cacheMapCombined=new n.FourKeyMap,this._pages=[],this._activePages=[],this._workBoundingBox={top:0,left:0,bottom:0,right:0},this._workAttributeData=new h.AttributeData,this._textureSize=512,this._onAddTextureAtlasCanvas=new l.Emitter,this.onAddTextureAtlasCanvas=this._onAddTextureAtlasCanvas.event,this._onRemoveTextureAtlasCanvas=new l.Emitter,this.onRemoveTextureAtlasCanvas=this._onRemoveTextureAtlasCanvas.event,this._requestClearModel=false,this._clearModelGeneration=0,this._createNewPage(),this._tmpCanvas=p(t3,4*this._config.deviceCellWidth+4,this._config.deviceCellHeight+4),this._tmpCtx=(0,a.throwIfFalsy)(this._tmpCanvas.getContext("2d",{alpha:this._config.allowTransparency,willReadFrequently:true}))}dispose(){this._tmpCanvas.remove();for(const t3 of this.pages)t3.canvas.remove();this._onAddTextureAtlasCanvas.dispose(),this._onRemoveTextureAtlasCanvas.dispose()}warmUp(){this._didWarmUp||(this._doWarmUp(),this._didWarmUp=true)}_doWarmUp(){const t3=new L.IdleTaskQueue(this._logService);for(let e3=33;e3<126;e3++)t3.enqueue(()=>{if(!this._cacheMap.get(e3,T.DEFAULT_COLOR,T.DEFAULT_COLOR,T.DEFAULT_EXT)){const t4=this._drawToCache(e3,T.DEFAULT_COLOR,T.DEFAULT_COLOR,T.DEFAULT_EXT,false,void 0);this._cacheMap.set(e3,T.DEFAULT_COLOR,T.DEFAULT_COLOR,T.DEFAULT_EXT,t4)}})}beginFrame(){const t3=this._requestClearModel;return this._requestClearModel=false,t3}clearTexture(){if(this._pages.some(t3=>t3._glyphs.length>0||0!==t3.currentRow.x||0!==t3.currentRow.y)){this._evictAllPages();this._createNewPage()}}_evictAllPages(){for(const t3 of this._pages)this._onRemoveTextureAtlasCanvas.fire(t3.canvas),t3.canvas.remove();this._pages.length=0,this._activePages.length=0,this._overflowSizePage=void 0,this._cacheMap.clear(),this._cacheMapCombined.clear(),this._didWarmUp=false,this._requestClearModel=true,this._clearModelGeneration++}_createNewPage(){if(_.maxAtlasPages&&this._pages.length>=_.maxAtlasPages){const t4=this._pages.filter(t5=>2*t5.canvas.width<=(_.maxTextureSize||4096)).sort((t5,e4)=>e4.canvas.width!==t5.canvas.width?e4.canvas.width-t5.canvas.width:e4.percentageUsed-t5.percentageUsed);let e3=-1,i3=0;for(let s4=0;s4t5.canvas.width!==s3[0].canvas.width))this._evictAllPages();else{const r2=s3.map(t5=>t5.glyphs[0].texturePage).sort((t5,e4)=>t5-e4),a2=this.pages.length-s3.length,o2=this._mergePages(s3,a2);o2.version=++Q.nextVersion;for(let t5=r2.length-1;t5>=0;t5--)this._deletePage(r2[t5]);this.pages.push(o2),this._requestClearModel=true,this._clearModelGeneration++,this._onAddTextureAtlasCanvas.fire(o2.canvas)}}const t3=new Q(this._document,this._textureSize);return this._pages.push(t3),this._activePages.push(t3),this._onAddTextureAtlasCanvas.fire(t3.canvas),t3}_mergePages(t3,e3){const i3=2*t3[0].canvas.width,s3=new Q(this._document,i3,t3);for(const[r2,a2]of t3.entries()){const t4=r2*a2.canvas.width%i3,o2=Math.floor(r2/2)*a2.canvas.height;s3.ctx.drawImage(a2.canvas,t4,o2);for(const s4 of a2.glyphs)s4.texturePage=e3,s4.sizeClipSpace.x=s4.size.x/i3,s4.sizeClipSpace.y=s4.size.y/i3,s4.texturePosition.x+=t4,s4.texturePosition.y+=o2,s4.texturePositionClipSpace.x=s4.texturePosition.x/i3,s4.texturePositionClipSpace.y=s4.texturePosition.y/i3;this._onRemoveTextureAtlasCanvas.fire(a2.canvas);const n2=this._activePages.indexOf(a2);-1!==n2&&this._activePages.splice(n2,1)}return s3}_deletePage(t3){this._pages.splice(t3,1);for(let e3=t3;e3=this._config.colors.ansi.length)throw new Error("No color found for idx "+t3);return this._config.colors.ansi[t3]}_getBackgroundColor(t3,e3,i3,s3){if(this._config.allowTransparency)return o.NULL_COLOR;let r2;switch(t3){case 16777216:case 33554432:r2=this._getColorFromAnsiIndex(e3);break;case 50331648:const t4=h.AttributeData.toColorRGB(e3);r2=o.channels.toColor(t4[0],t4[1],t4[2]);break;default:r2=i3?o.color.opaque(this._config.colors.foreground):this._config.colors.background}return this._config.allowTransparency||(r2=o.color.opaque(r2)),r2}_getForegroundColor(t3,e3,i3,r2,a2,n2,L2,T2,l2,d2){const c2=this._getMinimumContrastColor(t3,e3,i3,r2,a2,n2,L2,l2,T2,d2);if(c2)return c2;let _2;switch(a2){case 16777216:case 33554432:;this._config.drawBoldTextInBrightColors&&l2&&n2<8&&(n2+=8),_2=this._getColorFromAnsiIndex(n2);break;case 50331648:const t4=h.AttributeData.toColorRGB(n2);_2=o.channels.toColor(t4[0],t4[1],t4[2]);break;default:_2=L2?this._config.colors.background:this._config.colors.foreground}return this._config.allowTransparency&&(_2=o.color.opaque(_2)),T2&&(_2=o.color.multiplyOpacity(_2,s2.DIM_OPACITY)),_2}_resolveBackgroundRgba(t3,e3,i3){switch(t3){case 16777216:case 33554432:return this._getColorFromAnsiIndex(e3).rgba;case 50331648:return e3<<8;default:return i3?this._config.colors.foreground.rgba:this._config.colors.background.rgba}}_resolveForegroundRgba(t3,e3,i3,s3){switch(t3){case 16777216:case 33554432:return this._config.drawBoldTextInBrightColors&&s3&&e3<8&&(e3+=8),this._getColorFromAnsiIndex(e3).rgba;case 50331648:return e3<<8;default:return i3?this._config.colors.background.rgba:this._config.colors.foreground.rgba}}_getMinimumContrastColor(t3,e3,i3,s3,r2,a2,n2,L2,h2,T2){if(1===this._config.minimumContrastRatio||T2)return;const l2=this._getContrastCache(h2),d2=l2.getColor(t3,s3);if(void 0!==d2)return d2??void 0;const c2=this._resolveBackgroundRgba(e3,i3,n2),_2=this._resolveForegroundRgba(r2,a2,n2,L2),Q2=o.rgba.ensureContrastRatio(c2,_2,this._config.minimumContrastRatio/(h2?2:1));if(!Q2)return void l2.setColor(t3,s3,null);const u2=o.channels.toColor(Q2>>24&255,Q2>>16&255,Q2>>8&255);return l2.setColor(t3,s3,u2),u2}_getContrastCache(t3){return t3?this._config.colors.halfContrastCache:this._config.colors.contrastCache}_drawToCache(t3,e3,i3,o2,n2,L2){const T2="number"==typeof t3?String.fromCharCode(t3):t3;L2&&this._tmpCanvas.parentElement!==L2&&(this._tmpCanvas.style.display="none",L2.append(this._tmpCanvas));const l2=Math.min(this._config.deviceCellWidth*Math.max(T2.length,2)+4,this._config.deviceMaxTextureSize);this._tmpCanvas.width{orcaProbeWeight=String(orcaProbeWeight);let orcaActualWeightToken=this._tmpCtx.font.match(/(?:^|\s)(normal|bold|[1-9]\d{0,3})(?=\s+\d+(?:\.\d+)?px(?:\s|$))/)?.[1]??"400",orcaActualWeight=orcaActualWeightToken==="normal"?"400":orcaActualWeightToken==="bold"?"700":orcaActualWeightToken;if(/^(?:[1-8]\d{2}|900)$/.test(orcaProbeWeight)&&orcaActualWeight!==orcaProbeWeight){this.fontProbeMismatchCount=(this.fontProbeMismatchCount||0)+1;this.fontProbeLastMismatch={desired:orcaProbeWeight,actual:this._tmpCtx.font};try{globalThis.__orcaAtlasFontProbe&&globalThis.__orcaAtlasFontProbe(this.fontProbeLastMismatch)}catch(orcaFontProbeError){}}})(R),this._tmpCtx.textBaseline=s2.TEXT_BASELINE;const A=1===T2.length&&(0,a.isPowerlineGlyph)(T2.charCodeAt(0)),Z=1===T2.length&&(0,a.isRestrictedPowerlineGlyph)(T2.charCodeAt(0)),D=this._getForegroundColor(e3,b,x,i3,w,m,g,M,p2,(0,a.treatGlyphAsBackgroundColor)(T2.charCodeAt(0)));this._tmpCtx.fillStyle=D.css;const S=Z?0:4;let O=false;if(false!==this._config.customGlyphs){const t4=this._workAttributeData.getUnderlineVariantOffset();O=(0,r.tryDrawCustomGlyph)(this._tmpCtx,T2,S,S,this._config.deviceCellWidth,this._config.deviceCellHeight,this._config.deviceCharWidth,this._config.deviceCharHeight,this._config.fontSize,this._config.devicePixelRatio,this._logService,E.css,t4)}let I,W=!A;if(I="number"==typeof t3?this._unicodeService.wcwidth(t3):this._unicodeService.getStringCellWidth(t3),v){this._tmpCtx.save();const t4=Math.max(1,Math.floor(this._config.fontSize*this._config.devicePixelRatio/15)),e4=t4%2==1?.5:0;if(this._tmpCtx.lineWidth=t4,this._workAttributeData.isUnderlineColorDefault())this._tmpCtx.strokeStyle=this._tmpCtx.fillStyle;else if(this._workAttributeData.isUnderlineColorRGB())W=false,this._tmpCtx.strokeStyle=`rgb(${h.AttributeData.toColorRGB(this._workAttributeData.getUnderlineColor()).join(",")})`;else{W=false;let t5=this._workAttributeData.getUnderlineColor();this._config.drawBoldTextInBrightColors&&this._workAttributeData.isBold()&&t5<8&&(t5+=8),this._tmpCtx.strokeStyle=this._getColorFromAnsiIndex(t5).css};this._tmpCtx.fillStyle=this._tmpCtx.strokeStyle,this._tmpCtx.beginPath();const i4=S,s3=Math.ceil(S+this._config.deviceCharHeight)-e4-(n2?2*t4:0),r2=s3+2*t4;let o3=this._workAttributeData.getUnderlineVariantOffset(),L3=0,l3=0;for(let e5=0;e5=t4?2*t4-o3:t4-o3;false==!(o3>=t4)||0===_2?(this._tmpCtx.setLineDash([Math.round(t4),Math.round(t4)]),this._tmpCtx.moveTo(h2+_2,s3),this._tmpCtx.lineTo(T3,s3)):(this._tmpCtx.setLineDash([Math.round(t4),Math.round(t4)]),this._tmpCtx.moveTo(h2,s3),this._tmpCtx.lineTo(h2+_2,s3),this._tmpCtx.moveTo(h2+_2+t4,s3),this._tmpCtx.lineTo(T3,s3)),o3=(0,a.computeNextVariantOffset)(T3-h2,t4,o3);break;case 5:const Q2=.6,u2=.3,p3=T3-h2,g2=Math.floor(Q2*p3),M2=Math.floor(u2*p3),y2=p3-g2-M2;this._tmpCtx.setLineDash([g2,M2,y2]),this._tmpCtx.moveTo(h2,s3),this._tmpCtx.lineTo(T3,s3);break;default:;this._tmpCtx.moveTo(h2,s3),this._tmpCtx.lineTo(T3,s3)};n3||this._tmpCtx.stroke(),this._tmpCtx.restore()}if(this._tmpCtx.restore(),!O&&this._config.fontSize>=12&&!this._config.allowTransparency&&" "!==T2){;this._tmpCtx.save(),this._tmpCtx.textBaseline="alphabetic";const e5=this._tmpCtx.measureText(T2);if(this._tmpCtx.restore(),"actualBoundingBoxDescent"in e5&&e5.actualBoundingBoxDescent>0){this._tmpCtx.save();const e6=new Path2D;e6.rect(i4,L3-Math.ceil(t4/2),this._config.deviceCellWidth*I,l3-L3+Math.ceil(t4/2)),this._tmpCtx.clip(e6),this._tmpCtx.lineWidth=3*this._config.devicePixelRatio,this._tmpCtx.strokeStyle=E.css,this._tmpCtx.strokeText(T2,S,S+this._config.deviceCharHeight),this._tmpCtx.restore()}}}if(C){const t4=Math.max(1,Math.floor(this._config.fontSize*this._config.devicePixelRatio/15)),e4=t4%2==1?.5:0;this._tmpCtx.lineWidth=t4,this._tmpCtx.strokeStyle=this._tmpCtx.fillStyle,this._tmpCtx.beginPath(),this._tmpCtx.moveTo(S,S+e4),this._tmpCtx.lineTo(S+this._config.deviceCharWidth*I,S+e4),this._tmpCtx.stroke()}if(O||this._tmpCtx.fillText(T2,S,S+this._config.deviceCharHeight),"_"===T2&&!this._config.allowTransparency){let t4=u(this._tmpCtx.getImageData(S,S,this._config.deviceCellWidth,this._config.deviceCellHeight),E,D,W);if(t4)for(let e4=1;e4<=5&&(this._tmpCtx.save(),this._tmpCtx.fillStyle=E.css,this._tmpCtx.fillRect(0,0,this._tmpCanvas.width,this._tmpCanvas.height),this._tmpCtx.restore(),this._tmpCtx.fillText(T2,S,S+this._config.deviceCharHeight-e4),t4=u(this._tmpCtx.getImageData(S,S,this._config.deviceCellWidth,this._config.deviceCellHeight),E,D,W),t4);e4++);}if(f){const t4=Math.max(1,Math.floor(this._config.fontSize*this._config.devicePixelRatio/10)),e4=this._tmpCtx.lineWidth%2==1?.5:0;this._tmpCtx.lineWidth=t4,this._tmpCtx.strokeStyle=this._tmpCtx.fillStyle,this._tmpCtx.beginPath(),this._tmpCtx.moveTo(S,S+Math.floor(this._config.deviceCharHeight/2)-e4),this._tmpCtx.lineTo(S+this._config.deviceCharWidth*I,S+Math.floor(this._config.deviceCharHeight/2)-e4),this._tmpCtx.stroke()}this._tmpCtx.restore();const N=this._tmpCtx.getImageData(0,0,this._tmpCanvas.width,this._tmpCanvas.height);let P;if(P=this._config.allowTransparency?(function(t4){for(let e4=0;e40)return false;return true})(N):u(N,E,D,W),P)return d;const B=this._findGlyphBoundingBox(N,this._workBoundingBox,l2,Z,O,S);let $,F;for(;;){if(0===this._activePages.length){const t4=this._createNewPage();$=t4,F=t4.currentRow,F.height=B.size.y;break};$=this._activePages[this._activePages.length-1],F=$.currentRow;for(const t4 of this._activePages)B.size.y<=t4.currentRow.height&&($=t4,F=t4.currentRow);for(let t4=this._activePages.length-1;t4>=0;t4--)for(const e4 of this._activePages[t4].fixedRows)e4.height<=F.height&&B.size.y<=e4.height&&($=this._activePages[t4],F=e4);if(B.size.x>this._textureSize){;this._overflowSizePage||(_.maxAtlasPages&&this._pages.length>=_.maxAtlasPages&&this._evictAllPages(),this._overflowSizePage=new Q(this._document,this._config.deviceMaxTextureSize),this.pages.push(this._overflowSizePage),this._requestClearModel=true,this._clearModelGeneration++,this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas)),$=this._overflowSizePage,F=this._overflowSizePage.currentRow,F.x+B.size.x>=$.canvas.width&&(F.x=0,F.y+=F.height,F.height=0);break}if(F.y+B.size.y>=$.canvas.height||F.height>B.size.y+2){let t4=false;if($.currentRow.y+$.currentRow.height+B.size.y>=$.canvas.height){let e4;for(const t5 of this._activePages)if(t5.currentRow.y+t5.currentRow.height+B.size.y=_.maxAtlasPages&&F.y+B.size.y<=$.canvas.height&&F.height>=B.size.y&&F.x+B.size.x<=$.canvas.width)t4=true;else{const e5=this._createNewPage();$=e5,F=e5.currentRow,F.height=B.size.y,t4=true}}t4||($.currentRow.height>0&&$.fixedRows.push($.currentRow),F={x:0,y:$.currentRow.y+$.currentRow.height,height:B.size.y},$.fixedRows.push(F),$.currentRow={x:0,y:F.y+F.height,height:0})}if(F.x+B.size.x<=$.canvas.width)break;F===$.currentRow?(F.x=0,F.y+=F.height,F.height=0):$.fixedRows.splice($.fixedRows.indexOf(F),1)}return B.texturePage=this._pages.indexOf($),B.texturePosition.x=F.x,B.texturePosition.y=F.y,B.texturePositionClipSpace.x=F.x/$.canvas.width,B.texturePositionClipSpace.y=F.y/$.canvas.height,B.sizeClipSpace.x/=$.canvas.width,B.sizeClipSpace.y/=$.canvas.height,F.height=Math.max(F.height,B.size.y),F.x+=B.size.x,$.ctx.putImageData(N,B.texturePosition.x-this._workBoundingBox.left,B.texturePosition.y-this._workBoundingBox.top,this._workBoundingBox.left,this._workBoundingBox.top,B.size.x,B.size.y),$.addGlyph(B),$.version=++Q.nextVersion,B}_findGlyphBoundingBox(t3,e3,i3,s3,r2,a2){e3.top=0;const o2=s3?this._config.deviceCellHeight:this._tmpCanvas.height,n2=s3?this._config.deviceCellWidth:i3;let L2=false;for(let i4=0;i4=a2;i4--){for(let s4=0;s4=0;i4--){for(let s4=0;s4>>24,a2=e3.rgba>>>16&255,o2=e3.rgba>>>8&255,n2=i3.rgba>>>24,L2=i3.rgba>>>16&255,h2=i3.rgba>>>8&255,T2=Math.floor((Math.abs(r2-n2)+Math.abs(a2-L2)+Math.abs(o2-h2))/12);let l2=true;for(let e4=0;e4this._handleColorChange())),this._cellColorResolver=new s2.CellColorResolver(this._terminal,this._optionsService,this._model.selection,this._decorationService,this._coreBrowserService,this._themeService),this._core=this._terminal._core,this._renderLayers=[new _.LinkRenderLayer(this._core.screenElement,2,this._terminal,this._core.linkifier,this._coreBrowserService,d2,this._themeService)],this.dimensions=(0,g.createRenderDimensions)(),this._devicePixelRatio=this._coreBrowserService.dpr,this._updateDimensions(),this._updateCursorBlink(),this._register(d2.onOptionChange(()=>this._handleOptionsChanged())),this._textBlinkStateManager=this._register(new T.TextBlinkStateManager(()=>this._requestRedrawViewport(),this._coreBrowserService,this._optionsService)),this._resetBlinkingRowState(),this._deviceMaxTextureSize=this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE),this._register((0,u.addDisposableListener)(this._canvas,"webglcontextlost",t4=>{;this._logService.debug("webglcontextlost event received"),t4.preventDefault(),this._contextRestorationTimeout=setTimeout(()=>{;this._contextRestorationTimeout=void 0,this._logService.warn("webgl context not restored; firing onContextLoss"),this._onContextLoss.fire(t4)},3e3)})),this._register((0,u.addDisposableListener)(this._canvas,"webglcontextrestored",t4=>{;this._logService.warn("webglcontextrestored event received"),clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0,(0,r.removeTerminalFromCache)(this._terminal),this._initializeWebGLState(),this._requestRedrawViewport()})),this._observerDisposable.value=(0,o.observeDevicePixelDimensions)(this._canvas,this._coreBrowserService.window,(t4,e4)=>this._setCanvasDevicePixelDimensions(t4,e4)),this._register(this._coreBrowserService.onWindowChange(t4=>{this._observerDisposable.value=(0,o.observeDevicePixelDimensions)(this._canvas,t4,(t5,e4)=>this._setCanvasDevicePixelDimensions(t5,e4))})),this._register((0,u.addDisposableListener)(this._coreBrowserService.mainDocument,"mousedown",()=>this._cursorBlinkStateManager.value?.restartBlinkAnimation())),this._core.screenElement.appendChild(this._canvas),[this._rectangleRenderer.value,this._glyphRenderer.value]=this._initializeWebGLState(),this._isAttached=this._core.screenElement.isConnected,this._register((0,p.toDisposable)(()=>{;clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0;for(const t4 of this._renderLayers)t4.dispose();this._canvas.parentElement?.removeChild(this._canvas),(0,r.removeTerminalFromCache)(this._terminal)}))}get textureAtlas(){return this._charAtlas?.pages[0].canvas}_handleColorChange(){;this._refreshCharAtlas(),this._clearModel(true)}handleDevicePixelRatioChange(){this._devicePixelRatio!==this._coreBrowserService.dpr&&(this._devicePixelRatio=this._coreBrowserService.dpr,this.handleResize(this._terminal.cols,this._terminal.rows))}handleResize(t3,e3){;this._updateDimensions(),this._model.resize(this._terminal.cols,this._terminal.rows),this._resetBlinkingRowState();for(const t4 of this._renderLayers)t4.resize(this._terminal,this.dimensions);this._canvas.width=this.dimensions.device.canvas.width,this._canvas.height=this.dimensions.device.canvas.height,this._canvas.style.width=`${this.dimensions.css.canvas.width}px`,this._canvas.style.height=`${this.dimensions.css.canvas.height}px`,this._core.screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._core.screenElement.style.height=`${this.dimensions.css.canvas.height}px`,this._rectangleRenderer.value?.setDimensions(this.dimensions),this._rectangleRenderer.value?.handleResize(),this._glyphRenderer.value?.setDimensions(this.dimensions),this._glyphRenderer.value?.handleResize(),this._refreshCharAtlas(),this._clearModel(false),this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:true})}handleCharSizeChanged(){this.handleResize(this._terminal.cols,this._terminal.rows)}handleBlur(){for(const t3 of this._renderLayers)t3.handleBlur(this._terminal);this._cursorBlinkStateManager.value?.pause(),this._requestRedrawViewport()}handleFocus(){for(const t3 of this._renderLayers)t3.handleFocus(this._terminal);this._cursorBlinkStateManager.value?.resume(),this._requestRedrawViewport()}handleViewportVisibilityChange(t3){this._textBlinkStateManager.setViewportVisible(t3)}handleSelectionChanged(t3,e3,i3){for(const s3 of this._renderLayers)s3.handleSelectionChanged(this._terminal,t3,e3,i3);this._model.selection.update(this._core,t3,e3,i3),this._requestRedrawViewport()}handleCursorMove(){for(const t3 of this._renderLayers)t3.handleCursorMove(this._terminal);this._cursorBlinkStateManager.value?.restartBlinkAnimation()}_handleOptionsChanged(){;this._updateDimensions(),this._refreshCharAtlas(),this._updateCursorBlink()}_initializeWebGLState(){return this._rectangleRenderer.value=new d.RectangleRenderer(this._terminal,this._gl,this.dimensions,this._themeService,this._logService),this._glyphRenderer.value=new l.GlyphRenderer(this._terminal,this._gl,this.dimensions,this._optionsService,this._logService),this.handleCharSizeChanged(),[this._rectangleRenderer.value,this._glyphRenderer.value]}_refreshCharAtlas(){if(this.dimensions.device.char.width<=0&&this.dimensions.device.char.height<=0)return void(this._isAttached=false);const t3=(0,r.acquireTextureAtlas)(this._terminal,this._optionsService.rawOptions,this._themeService.colors,this.dimensions.device.cell.width,this.dimensions.device.cell.height,this.dimensions.device.char.width,this.dimensions.device.char.height,this._coreBrowserService.dpr,this._deviceMaxTextureSize,this._customGlyphs);this._charAtlas!==t3&&(this._onChangeTextureAtlas.fire(t3.pages[0].canvas),this._charAtlasDisposable.value=(0,p.combinedDisposable)(Q.EventUtils.forward(t3.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas),Q.EventUtils.forward(t3.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas))),this._charAtlas=t3,this._charAtlas.warmUp(),this._glyphRenderer.value?.setAtlas(this._charAtlas)}_clearModel(t3){;this._model.clear(),t3&&this._glyphRenderer.value?.clear()}clearTextureAtlas(){;this._charAtlas?.clearTexture(),this._clearModel(true),this._requestRedrawViewport()}clear(){this._clearModel(true);for(const t3 of this._renderLayers)t3.reset(this._terminal);this._resetBlinkingRowState(),this._textBlinkStateManager.setNeedsBlinkInViewport(false),this._cursorBlinkStateManager.value?.restartBlinkAnimation(),this._updateCursorBlink()}renderRows(t3,e3){if(!this._isAttached){if(!(this._core.screenElement?.isConnected&&this._charSizeService.width&&this._charSizeService.height))return;this._updateDimensions(),this._refreshCharAtlas(),this._isAttached=true}for(const i4 of this._renderLayers)i4.handleGridChanged(this._terminal,t3,e3);if(!this._glyphRenderer.value||!this._rectangleRenderer.value)return;this._glyphRenderer.value.beginFrame()?(this._clearModel(true),this._updateModel(0,this._terminal.rows-1)):this._updateModel(t3,e3);let i3=false,s3=0;for(;this._charAtlas&&s3++<32&&this._glyphRenderer.value.beginFrame();)i3=true,this._clearModel(true),this._updateModel(0,this._terminal.rows-1);i3&&this._glyphRenderer.value.invalidateAtlasTextures(),this._rectangleRenderer.value.renderBackgrounds(),this._glyphRenderer.value.render(this._model),this._cursorBlinkStateManager.value&&!this._cursorBlinkStateManager.value.isCursorVisible||this._rectangleRenderer.value.renderCursor()}_updateCursorBlink(){;this._coreService.decPrivateModes.cursorBlink??this._terminal.options.cursorBlink?this._cursorBlinkStateManager.value=new a.CursorBlinkStateManager(()=>{this._requestRedrawCursor()},this._coreBrowserService):this._cursorBlinkStateManager.clear(),this._requestRedrawCursor()}_updateModel(t3,e3){const i3=this._core;let s3,r2,a2,o2,n2,L2,T2,l2,d2,_2,Q2,u2,p2,g2,M2,f,C,m=this._workCell;t3=v(t3,i3.rows-1,0),e3=v(e3,i3.rows-1,0);const w=this._coreService.decPrivateModes.cursorStyle??i3.options.cursorStyle??"block",x=this._terminal.buffer.active.baseY+this._terminal.buffer.active.cursorY,b=x-i3.buffer.ydisp,E=Math.min(this._terminal.buffer.active.cursorX,i3.cols-1);let R=-1;const k=this._coreService.isCursorInitialized&&!this._coreService.isCursorHidden&&(!this._cursorBlinkStateManager.value||this._cursorBlinkStateManager.value.isCursorVisible);this._model.cursor=void 0;let A=false;for(r2=t3;r2<=e3;r2++){a2=r2+i3.buffer.ydisp;const t4=i3.buffer.lines.get(a2);if(!t4){for(this._model.lineLengths[r2]=0,f=0;f=T2,d2=f,n2.length>0&&f===n2[0][0]&&l2){_2=n2.shift();const t5=this._model.selection.isCellSelected(this._terminal,_2[0],a2);for(M2=_2[0]+1;M2<_2[1];M2++)l2&&=t5===this._model.selection.isCellSelected(this._terminal,M2,a2);l2&&=!Q2||E<_2[0]||E>=_2[1],l2?(L2=true,m=new y(m,o2.translateToString(true,_2[0],_2[1]),_2[1]-_2[0]),d2=_2[1]-1):T2=_2[1]}if(u2=m.getChars(),p2=m.getCode(),M2=4*(r2*i3.cols+f),!e4&&m.isBlink()&&(e4=true),this._cellColorResolver.resolve(m,f,a2,this.dimensions.device.cell.width,this.dimensions.device.cell.height),k&&a2===x&&(f===E&&(this._model.cursor={x:E,y:b,width:m.getWidth(),style:this._coreBrowserService.isFocused?w:i3.options.cursorInactiveStyle,cursorWidth:i3.options.cursorWidth,dpr:this._devicePixelRatio},R=E+m.getWidth()-1),f>=E&&f<=R&&(this._coreBrowserService.isFocused&&"block"===w||false===this._coreBrowserService.isFocused&&"block"===i3.options.cursorInactiveStyle)&&(this._cellColorResolver.result.fg=50331648|this._themeService.colors.cursorAccent.rgba>>8&16777215,this._cellColorResolver.result.bg=50331648|this._themeService.colors.cursor.rgba>>8&16777215)),this._textBlinkStateManager.isEnabled&&!this._textBlinkStateManager.isBlinkOn&&m.isBlink()&&(this._cellColorResolver.result.fg|=1073741824),p2!==h.NULL_CELL_CODE&&(this._model.lineLengths[r2]=f+1),(this._model.cells[M2]!==p2||this._model.cells[M2+1]!==this._cellColorResolver.result.bg||this._model.cells[M2+2]!==this._cellColorResolver.result.fg||this._model.cells[M2+3]!==this._cellColorResolver.result.ext)&&(A=true,u2.length>1&&(p2|=c.COMBINED_CHAR_BIT_MASK),this._model.cells[M2]=p2,this._model.cells[M2+1]=this._cellColorResolver.result.bg,this._model.cells[M2+2]=this._cellColorResolver.result.fg,this._model.cells[M2+3]=this._cellColorResolver.result.ext,g2=m.getWidth(),this._glyphRenderer.value.updateCell(f,r2,p2,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext,u2,g2,s3),L2)){for(m=this._workCell,f++;f<=d2;f++)C=4*(r2*i3.cols+f),this._nullModelCell(f,r2,C,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext);f--}}this._setRowBlinkState(r2,e4)};A&&this._rectangleRenderer.value.updateBackgrounds(this._model),this._rectangleRenderer.value.updateCursor(this._model),this._updateTextBlinkState()}_nullModelCell(t3,e3,i3,s3,r2,a2){;this._glyphRenderer.value.updateCell(t3,e3,h.NULL_CELL_CODE,s3,r2,a2,h.NULL_CELL_CHAR,0,0),this._model.cells[i3]=h.NULL_CELL_CODE,this._model.cells[i3+1]=s3,this._model.cells[i3+2]=r2,this._model.cells[i3+3]=a2}_resetBlinkingRowState(){;this._rowHasBlinkingCells=new Array(this._terminal.rows).fill(false),this._rowHasBlinkingCellsCount=0}_setRowBlinkState(t3,e3){this._rowHasBlinkingCells[t3]!==e3&&(this._rowHasBlinkingCells[t3]=e3,this._rowHasBlinkingCellsCount+=e3?1:-1)}_updateTextBlinkState(){this._textBlinkStateManager.setNeedsBlinkInViewport(this._rowHasBlinkingCellsCount>0)}_updateDimensions(){this._charSizeService.width&&this._charSizeService.height&&(this.dimensions.device.char.width=Math.floor(this._charSizeService.width*this._devicePixelRatio),this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*this._devicePixelRatio),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.top=1===this._optionsService.rawOptions.lineHeight?0:Math.round((this.dimensions.device.cell.height-this.dimensions.device.char.height)/2),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.char.left=Math.floor(this._optionsService.rawOptions.letterSpacing/2),this.dimensions.device.canvas.height=this._terminal.rows*this.dimensions.device.cell.height,this.dimensions.device.canvas.width=this._terminal.cols*this.dimensions.device.cell.width,this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/this._devicePixelRatio),this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/this._devicePixelRatio),this.dimensions.css.cell.height=this.dimensions.device.cell.height/this._devicePixelRatio,this.dimensions.css.cell.width=this.dimensions.device.cell.width/this._devicePixelRatio)}_setCanvasDevicePixelDimensions(t3,e3){;this._canvas.width===t3&&this._canvas.height===e3||(this._canvas.width=t3,this._canvas.height=e3,this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:true}))}_requestRedrawViewport(){this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1})}_requestRedrawCursor(){const t3=this._terminal.buffer.active.cursorY;this._onRequestRedraw.fire({start:t3,end:t3})}}e2.WebglRenderer=M;class y extends n.AttributeData{constructor(t3,e3,i3){;super(),this.content=0,this.combinedData="",this.fg=t3.fg,this.bg=t3.bg,this.combinedData=e3,this._width=i3}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(t3){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}function v(t3,e3,i3=0){return Math.max(Math.min(t3,e3),i3)}e2.JoinedCellData=y},719(t2,e2,i2){;Object.defineProperty(e2,"__esModule",{value:true}),e2.GLTexture=e2.PROJECTION_MATRIX=void 0,e2.createProgram=function(t3,e3,i3,a){const o=(0,s2.throwIfFalsy)(t3.createProgram());if(t3.attachShader(o,(0,s2.throwIfFalsy)(r(t3,t3.VERTEX_SHADER,e3,a))),t3.attachShader(o,(0,s2.throwIfFalsy)(r(t3,t3.FRAGMENT_SHADER,i3,a))),t3.linkProgram(o),t3.getProgramParameter(o,t3.LINK_STATUS))return o;a.error(t3.getProgramInfoLog(o)),t3.deleteProgram(o)},e2.createShader=r,e2.expandFloat32Array=function(t3,e3){const i3=Math.min(2*t3.length,e3),s3=new Float32Array(i3);for(let e4=0;e4{const e3=[],i3=[3/8,2/8,3/8],s3=[0,3/8,5/8];for(let r2=0;r2<3;r2++){const a=t3>>2*r2&1,o=t3>>2*r2+1&1;a&&o?e3.push(`M0,${s3[r2]} L1,${s3[r2]} L1,${s3[r2]+i3[r2]} L0,${s3[r2]+i3[r2]} Z`):a?e3.push(`M0,${s3[r2]} L0.5,${s3[r2]} L0.5,${s3[r2]+i3[r2]} L0,${s3[r2]+i3[r2]} Z`):o&&e3.push(`M0.5,${s3[r2]} L1,${s3[r2]} L1,${s3[r2]+i3[r2]} L0.5,${s3[r2]+i3[r2]} Z`)}return e3.join(" ")}}}function r(t3){const e3=[],i3=.15,s3=.015,r2=.075,a=.0375,o=.95;if(64&t3){const t4=.175,a2=.2125,n=.25,L=.2+s3,h=o-i3-s3;e3.push(`M${L},${a2} L${L+r2},${t4} L${h-r2},${t4} L${h},${a2} L${h-r2},${n} L${L+r2},${n} Z`)}if(32&t3){const t4=o-i3,s4=.875,r3=o,n=.265,L=.485;e3.push(`M${s4},${n} L${r3},${n+a} L${r3},${L-a} L${s4},${L} L${t4},${L-a} L${t4},${n+a} Z`)}if(16&t3){const t4=o-i3,s4=.875,r3=o,n=.515,L=.735;e3.push(`M${s4},${n} L${r3},${n+a} L${r3},${L-a} L${s4},${L} L${t4},${L-a} L${t4},${n+a} Z`)}if(8&t3){const t4=.75,a2=.7875,n=.825,L=.2+s3,h=o-i3-s3;e3.push(`M${L},${a2} L${L+r2},${t4} L${h-r2},${t4} L${h},${a2} L${h-r2},${n} L${L+r2},${n} Z`)}if(4&t3){const t4=.05,i4=.125,s4=.2,r3=.515,o2=.735;e3.push(`M${i4},${r3} L${s4},${r3+a} L${s4},${o2-a} L${i4},${o2} L${t4},${o2-a} L${t4},${r3+a} Z`)}if(2&t3){const t4=.05,i4=.125,s4=.2,r3=.265,o2=.485;e3.push(`M${i4},${r3} L${s4},${r3+a} L${s4},${o2-a} L${i4},${o2} L${t4},${o2-a} L${t4},${r3+a} Z`)}if(1&t3){const t4=.4625,a2=.5,n=.5375,L=.2+s3,h=o-i3-s3;e3.push(`M${L},${a2} L${L+r2},${t4} L${h-r2},${t4} L${h},${a2} L${h-r2},${n} L${L+r2},${n} Z`)}return e3.join(" ")};Object.defineProperty(e2,"__esModule",{value:true}),e2.blockPatternCodepoints=e2.customGlyphDefinitions=void 0,(function(t3){;t3.LINE_H=Object.freeze({type:2,data:"M0,.5 L1,.5",strokeWidth:1}),t3.LINE_V=Object.freeze({type:2,data:"M.5,0 L.5,1",strokeWidth:1}),t3.FADE_RIGHT=Object.freeze({type:2,data:"M0,.5 L.28,.5 M.32,.5 L.52,.5 M.60,.5 L.72,.5 M.84,.5 L.90,.5",strokeWidth:1}),t3.FADE_LEFT=Object.freeze({type:2,data:"M.10,.5 L.16,.5 M.28,.5 L.40,.5 M.48,.5 L.68,.5 M.72,.5 L1,.5",strokeWidth:1}),t3.FADE_DOWN=Object.freeze({type:2,data:"M.5,0 L.5,.28 M.5,.32 L.5,.52 M.5,.60 L.5,.72 M.5,.84 L.5,.90",strokeWidth:1}),t3.FADE_UP=Object.freeze({type:2,data:"M.5,.10 L.5,.16 M.5,.28 L.5,.40 M.5,.48 L.5,.68 M.5,.72 L.5,1",strokeWidth:1}),t3.CURVE_DOWN_RIGHT=Object.freeze({type:2,data:(t4,e3)=>`M.5,1 L.5,${.5+e3/.15*.5} C.5,${.5+e3/.15*.5},.5,.5,1,.5`,strokeWidth:1}),t3.CURVE_DOWN_LEFT=Object.freeze({type:2,data:(t4,e3)=>`M.5,1 L.5,${.5+e3/.15*.5} C.5,${.5+e3/.15*.5},.5,.5,0,.5`,strokeWidth:1}),t3.CURVE_UP_RIGHT=Object.freeze({type:2,data:(t4,e3)=>`M.5,0 L.5,${.5-e3/.15*.5} C.5,${.5-e3/.15*.5},.5,.5,1,.5`,strokeWidth:1}),t3.CURVE_UP_LEFT=Object.freeze({type:2,data:(t4,e3)=>`M.5,0 L.5,${.5-e3/.15*.5} C.5,${.5-e3/.15*.5},.5,.5,0,.5`,strokeWidth:1}),t3.NODE_FILL=Object.freeze({type:3,data:"M.85,.5 A.35,.175,0,1,1,.15,.5 A.35,.175,0,1,1,.85,.5"}),t3.NODE_STROKE=Object.freeze({type:3,data:"M.85,.5 A.35,.175,0,1,1,.15,.5 A.35,.175,0,1,1,.85,.5",strokeWidth:1}),t3.NODE_LINE_RIGHT=Object.freeze({type:3,data:"M1,.5 L.85,.5",strokeWidth:1}),t3.NODE_LINE_LEFT=Object.freeze({type:3,data:"M0,.5 L.15,.5",strokeWidth:1}),t3.NODE_LINE_DOWN=Object.freeze({type:3,data:"M.5,1 L.5,.7",strokeWidth:1}),t3.NODE_LINE_UP=Object.freeze({type:3,data:"M.5,0 L.5,.3",strokeWidth:1})})(i2||(i2={})),e2.customGlyphDefinitions={"\u2500":{type:2,data:"M0,.5 L1,.5",strokeWidth:1},"\u2501":{type:2,data:"M0,.5 L1,.5",strokeWidth:3},"\u2502":{type:2,data:"M.5,0 L.5,1",strokeWidth:1},"\u2503":{type:2,data:"M.5,0 L.5,1",strokeWidth:3},"\u2504":{type:2,data:"M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5",strokeWidth:1},"\u2505":{type:2,data:"M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5",strokeWidth:3},"\u2506":{type:2,data:"M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333",strokeWidth:1},"\u2507":{type:2,data:"M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333",strokeWidth:3},"\u2508":{type:2,data:"M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5",strokeWidth:1},"\u2509":{type:2,data:"M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5",strokeWidth:3},"\u250A":{type:2,data:"M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95",strokeWidth:1},"\u250B":{type:2,data:"M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95",strokeWidth:3},"\u250C":{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:1},"\u250D":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u250E":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u250F":{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:3},"\u2510":{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:1},"\u2511":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u2512":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u2513":{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:3},"\u2514":{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:1},"\u2515":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u2516":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u2517":{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:3},"\u2518":{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:1},"\u2519":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u251A":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u251B":{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:3},"\u251C":{type:2,data:"M.5,0 L.5,1 M.5,.5 L1,.5",strokeWidth:1},"\u251D":[{type:2,data:"M.5,0 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u251E":[{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u251F":[{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u2520":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,1",strokeWidth:3}],"\u2521":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:3}],"\u2522":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:3}],"\u2523":{type:2,data:"M.5,0 L.5,1 M.5,.5 L1,.5",strokeWidth:3},"\u2524":{type:2,data:"M.5,0 L.5,1 M.5,.5 L0,.5",strokeWidth:1},"\u2525":[{type:2,data:"M.5,0 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u2526":[{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u2527":[{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u2528":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,1",strokeWidth:3}],"\u2529":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:3}],"\u252A":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:3}],"\u252B":{type:2,data:"M.5,0 L.5,1 M.5,.5 L0,.5",strokeWidth:3},"\u252C":{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,1",strokeWidth:1},"\u252D":[{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u252E":[{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u252F":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M0,.5 L1,.5",strokeWidth:3}],"\u2530":[{type:2,data:"M0,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u2531":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:3}],"\u2532":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:3}],"\u2533":{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,1",strokeWidth:3},"\u2534":{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,0",strokeWidth:1},"\u2535":[{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u2536":[{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u2537":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M0,.5 L1,.5",strokeWidth:3}],"\u2538":[{type:2,data:"M0,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u2539":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:3}],"\u253A":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:3}],"\u253B":{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,0",strokeWidth:3},"\u253C":{type:2,data:"M0,.5 L1,.5 M.5,0 L.5,1",strokeWidth:1},"\u253D":[{type:2,data:"M.5,0 L.5,1 M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u253E":[{type:2,data:"M.5,0 L.5,1 M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u253F":[{type:2,data:"M.5,0 L.5,1",strokeWidth:1},{type:2,data:"M0,.5 L1,.5",strokeWidth:3}],"\u2540":[{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u2541":[{type:2,data:"M.5,.5 L.5,0 M0,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u2542":[{type:2,data:"M0,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,1",strokeWidth:3}],"\u2543":[{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:3}],"\u2544":[{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:3}],"\u2545":[{type:2,data:"M.5,0 L.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M0,.5 L.5,.5 L.5,1",strokeWidth:3}],"\u2546":[{type:2,data:"M.5,0 L.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M0.5,1 L.5,.5 L1,.5",strokeWidth:3}],"\u2547":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0 M0,.5 L1,.5",strokeWidth:3}],"\u2548":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M0,.5 L1,.5 M.5,.5 L.5,1",strokeWidth:3}],"\u2549":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,1 M.5,.5 L0,.5",strokeWidth:3}],"\u254A":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,0 L.5,1 M.5,.5 L1,.5",strokeWidth:3}],"\u254B":{type:2,data:"M0,.5 L1,.5 M.5,0 L.5,1",strokeWidth:3},"\u254C":{type:2,data:"M.1,.5 L.4,.5 M.6,.5 L.9,.5",strokeWidth:1},"\u254D":{type:2,data:"M.1,.5 L.4,.5 M.6,.5 L.9,.5",strokeWidth:3},"\u254E":{type:2,data:"M.5,.1 L.5,.4 M.5,.6 L.5,.9",strokeWidth:1},"\u254F":{type:2,data:"M.5,.1 L.5,.4 M.5,.6 L.5,.9",strokeWidth:3},"\u2550":{type:2,data:(t3,e3)=>`M0,${.5-e3} L1,${.5-e3} M0,${.5+e3} L1,${.5+e3}`,strokeWidth:1},"\u2551":{type:2,data:(t3,e3)=>`M${.5-t3},0 L${.5-t3},1 M${.5+t3},0 L${.5+t3},1`,strokeWidth:1},"\u2552":{type:2,data:(t3,e3)=>`M.5,1 L.5,${.5-e3} L1,${.5-e3} M.5,${.5+e3} L1,${.5+e3}`,strokeWidth:1},"\u2553":{type:2,data:(t3,e3)=>`M${.5-t3},1 L${.5-t3},.5 L1,.5 M${.5+t3},.5 L${.5+t3},1`,strokeWidth:1},"\u2554":{type:2,data:(t3,e3)=>`M1,${.5-e3} L${.5-t3},${.5-e3} L${.5-t3},1 M1,${.5+e3} L${.5+t3},${.5+e3} L${.5+t3},1`,strokeWidth:1},"\u2555":{type:2,data:(t3,e3)=>`M0,${.5-e3} L.5,${.5-e3} L.5,1 M0,${.5+e3} L.5,${.5+e3}`,strokeWidth:1},"\u2556":{type:2,data:(t3,e3)=>`M${.5+t3},1 L${.5+t3},.5 L0,.5 M${.5-t3},.5 L${.5-t3},1`,strokeWidth:1},"\u2557":{type:2,data:(t3,e3)=>`M0,${.5+e3} L${.5-t3},${.5+e3} L${.5-t3},1 M0,${.5-e3} L${.5+t3},${.5-e3} L${.5+t3},1`,strokeWidth:1},"\u2558":{type:2,data:(t3,e3)=>`M.5,0 L.5,${.5+e3} L1,${.5+e3} M.5,${.5-e3} L1,${.5-e3}`,strokeWidth:1},"\u2559":{type:2,data:(t3,e3)=>`M1,.5 L${.5-t3},.5 L${.5-t3},0 M${.5+t3},.5 L${.5+t3},0`,strokeWidth:1},"\u255A":{type:2,data:(t3,e3)=>`M1,${.5-e3} L${.5+t3},${.5-e3} L${.5+t3},0 M1,${.5+e3} L${.5-t3},${.5+e3} L${.5-t3},0`,strokeWidth:1},"\u255B":{type:2,data:(t3,e3)=>`M0,${.5+e3} L.5,${.5+e3} L.5,0 M0,${.5-e3} L.5,${.5-e3}`,strokeWidth:1},"\u255C":{type:2,data:(t3,e3)=>`M0,.5 L${.5+t3},.5 L${.5+t3},0 M${.5-t3},.5 L${.5-t3},0`,strokeWidth:1},"\u255D":{type:2,data:(t3,e3)=>`M0,${.5-e3} L${.5-t3},${.5-e3} L${.5-t3},0 M0,${.5+e3} L${.5+t3},${.5+e3} L${.5+t3},0`,strokeWidth:1},"\u255E":{type:2,data:(t3,e3)=>`M.5,0 L.5,1 M.5,${.5-e3} L1,${.5-e3} M.5,${.5+e3} L1,${.5+e3}`,strokeWidth:1},"\u255F":{type:2,data:(t3,e3)=>`M${.5-t3},0 L${.5-t3},1 M${.5+t3},0 L${.5+t3},1 M${.5+t3},.5 L1,.5`,strokeWidth:1},"\u2560":{type:2,data:(t3,e3)=>`M${.5-t3},0 L${.5-t3},1 M1,${.5+e3} L${.5+t3},${.5+e3} L${.5+t3},1 M1,${.5-e3} L${.5+t3},${.5-e3} L${.5+t3},0`,strokeWidth:1},"\u2561":{type:2,data:(t3,e3)=>`M.5,0 L.5,1 M0,${.5-e3} L.5,${.5-e3} M0,${.5+e3} L.5,${.5+e3}`,strokeWidth:1},"\u2562":{type:2,data:(t3,e3)=>`M0,.5 L${.5-t3},.5 M${.5-t3},0 L${.5-t3},1 M${.5+t3},0 L${.5+t3},1`,strokeWidth:1},"\u2563":{type:2,data:(t3,e3)=>`M${.5+t3},0 L${.5+t3},1 M0,${.5+e3} L${.5-t3},${.5+e3} L${.5-t3},1 M0,${.5-e3} L${.5-t3},${.5-e3} L${.5-t3},0`,strokeWidth:1},"\u2564":{type:2,data:(t3,e3)=>`M0,${.5-e3} L1,${.5-e3} M0,${.5+e3} L1,${.5+e3} M.5,${.5+e3} L.5,1`,strokeWidth:1},"\u2565":{type:2,data:(t3,e3)=>`M0,.5 L1,.5 M${.5-t3},.5 L${.5-t3},1 M${.5+t3},.5 L${.5+t3},1`,strokeWidth:1},"\u2566":{type:2,data:(t3,e3)=>`M0,${.5-e3} L1,${.5-e3} M0,${.5+e3} L${.5-t3},${.5+e3} L${.5-t3},1 M1,${.5+e3} L${.5+t3},${.5+e3} L${.5+t3},1`,strokeWidth:1},"\u2567":{type:2,data:(t3,e3)=>`M.5,0 L.5,${.5-e3} M0,${.5-e3} L1,${.5-e3} M0,${.5+e3} L1,${.5+e3}`,strokeWidth:1},"\u2568":{type:2,data:(t3,e3)=>`M0,.5 L1,.5 M${.5-t3},.5 L${.5-t3},0 M${.5+t3},.5 L${.5+t3},0`,strokeWidth:1},"\u2569":{type:2,data:(t3,e3)=>`M0,${.5+e3} L1,${.5+e3} M0,${.5-e3} L${.5-t3},${.5-e3} L${.5-t3},0 M1,${.5-e3} L${.5+t3},${.5-e3} L${.5+t3},0`,strokeWidth:1},"\u256A":{type:2,data:(t3,e3)=>`M.5,0 L.5,1 M0,${.5-e3} L1,${.5-e3} M0,${.5+e3} L1,${.5+e3}`,strokeWidth:1},"\u256B":{type:2,data:(t3,e3)=>`M0,.5 L1,.5 M${.5-t3},0 L${.5-t3},1 M${.5+t3},0 L${.5+t3},1`,strokeWidth:1},"\u256C":{type:2,data:(t3,e3)=>`M0,${.5+e3} L${.5-t3},${.5+e3} L${.5-t3},1 M1,${.5+e3} L${.5+t3},${.5+e3} L${.5+t3},1 M0,${.5-e3} L${.5-t3},${.5-e3} L${.5-t3},0 M1,${.5-e3} L${.5+t3},${.5-e3} L${.5+t3},0`,strokeWidth:1},"\u256D":{type:2,data:(t3,e3)=>`M.5,1 L.5,${.5+e3/.15*.5} C.5,${.5+e3/.15*.5},.5,.5,1,.5`,strokeWidth:1},"\u256E":{type:2,data:(t3,e3)=>`M.5,1 L.5,${.5+e3/.15*.5} C.5,${.5+e3/.15*.5},.5,.5,0,.5`,strokeWidth:1},"\u256F":{type:2,data:(t3,e3)=>`M.5,0 L.5,${.5-e3/.15*.5} C.5,${.5-e3/.15*.5},.5,.5,0,.5`,strokeWidth:1},"\u2570":{type:2,data:(t3,e3)=>`M.5,0 L.5,${.5-e3/.15*.5} C.5,${.5-e3/.15*.5},.5,.5,1,.5`,strokeWidth:1},"\u2571":{type:2,data:"M1,0 L0,1",strokeWidth:1},"\u2572":{type:2,data:"M0,0 L1,1",strokeWidth:1},"\u2573":{type:2,data:"M1,0 L0,1 M0,0 L1,1",strokeWidth:1},"\u2574":{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},"\u2575":{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},"\u2576":{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},"\u2577":{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},"\u2578":{type:2,data:"M.5,.5 L0,.5",strokeWidth:3},"\u2579":{type:2,data:"M.5,.5 L.5,0",strokeWidth:3},"\u257A":{type:2,data:"M.5,.5 L1,.5",strokeWidth:3},"\u257B":{type:2,data:"M.5,.5 L.5,1",strokeWidth:3},"\u257C":[{type:2,data:"M.5,.5 L0,.5",strokeWidth:1},{type:2,data:"M.5,.5 L1,.5",strokeWidth:3}],"\u257D":[{type:2,data:"M.5,.5 L.5,0",strokeWidth:1},{type:2,data:"M.5,.5 L.5,1",strokeWidth:3}],"\u257E":[{type:2,data:"M.5,.5 L1,.5",strokeWidth:1},{type:2,data:"M.5,.5 L0,.5",strokeWidth:3}],"\u257F":[{type:2,data:"M.5,.5 L.5,1",strokeWidth:1},{type:2,data:"M.5,.5 L.5,0",strokeWidth:3}],"\u2580":{type:0,data:[{x:0,y:0,w:8,h:4}]},"\u2581":{type:0,data:[{x:0,y:7,w:8,h:1}]},"\u2582":{type:0,data:[{x:0,y:6,w:8,h:2}]},"\u2583":{type:0,data:[{x:0,y:5,w:8,h:3}]},"\u2584":{type:0,data:[{x:0,y:4,w:8,h:4}]},"\u2585":{type:0,data:[{x:0,y:3,w:8,h:5}]},"\u2586":{type:0,data:[{x:0,y:2,w:8,h:6}]},"\u2587":{type:0,data:[{x:0,y:1,w:8,h:7}]},"\u2588":{type:0,data:[{x:0,y:0,w:8,h:8}]},"\u2589":{type:0,data:[{x:0,y:0,w:7,h:8}]},"\u258A":{type:0,data:[{x:0,y:0,w:6,h:8}]},"\u258B":{type:0,data:[{x:0,y:0,w:5,h:8}]},"\u258C":{type:0,data:[{x:0,y:0,w:4,h:8}]},"\u258D":{type:0,data:[{x:0,y:0,w:3,h:8}]},"\u258E":{type:0,data:[{x:0,y:0,w:2,h:8}]},"\u258F":{type:0,data:[{x:0,y:0,w:1,h:8}]},"\u2590":{type:0,data:[{x:4,y:0,w:4,h:8}]},"\u2591":{type:1,data:[[1,0],[0,0]]},"\u2592":{type:1,data:[[1,0],[0,1]]},"\u2593":{type:1,data:[[1,1],[1,0]]},"\u2594":{type:0,data:[{x:0,y:0,w:8,h:1}]},"\u2595":{type:0,data:[{x:7,y:0,w:1,h:8}]},"\u2596":{type:0,data:[{x:0,y:4,w:4,h:4}]},"\u2597":{type:0,data:[{x:4,y:4,w:4,h:4}]},"\u2598":{type:0,data:[{x:0,y:0,w:4,h:4}]},"\u2599":{type:0,data:[{x:0,y:0,w:4,h:8},{x:0,y:4,w:8,h:4}]},"\u259A":{type:0,data:[{x:0,y:0,w:4,h:4},{x:4,y:4,w:4,h:4}]},"\u259B":{type:0,data:[{x:0,y:0,w:4,h:8},{x:4,y:0,w:4,h:4}]},"\u259C":{type:0,data:[{x:0,y:0,w:8,h:4},{x:4,y:0,w:4,h:8}]},"\u259D":{type:0,data:[{x:4,y:0,w:4,h:4}]},"\u259E":{type:0,data:[{x:4,y:0,w:4,h:4},{x:0,y:4,w:4,h:4}]},"\u259F":{type:0,data:[{x:4,y:0,w:4,h:8},{x:0,y:4,w:8,h:4}]},"\uE0A0":{type:5,data:{d:"M.3,1 L.03,1 L.03,.88 C.03,.82,.06,.78,.11,.73 C.15,.7,.2,.68,.28,.65 L.43,.6 C.49,.58,.53,.56,.56,.53 C.59,.5,.6,.47,.6,.43 L.6,.27 L.4,.27 L.69,.1 L.98,.27 L.78,.27 L.78,.46 C.78,.52,.76,.56,.72,.61 C.68,.66,.63,.67,.56,.7 L.48,.72 C.42,.74,.38,.76,.35,.78 C.32,.8,.31,.84,.31,.88 L.31,1 M.3,.5 L.03,.59 L.03,.09 L.3,.09 L.3,.655",type:0}},"\uE0A1":{type:5,data:{d:"M.7,.4 L.7,.47 L.2,.47 L.2,.03 L.355,.03 L.355,.4 L.705,.4 M.7,.5 L.86,.5 L.86,.95 L.69,.95 L.44,.66 L.46,.86 L.46,.95 L.3,.95 L.3,.49 L.46,.49 L.71,.78 L.69,.565 L.69,.5",type:0}},"\uE0A2":{type:5,data:{d:"M.25,.94 C.16,.94,.11,.92,.11,.87 L.11,.53 C.11,.48,.15,.455,.23,.45 L.23,.3 C.23,.25,.26,.22,.31,.19 C.36,.16,.43,.15,.51,.15 C.59,.15,.66,.16,.71,.19 C.77,.22,.79,.26,.79,.3 L.79,.45 C.87,.45,.91,.48,.91,.53 L.91,.87 C.91,.92,.86,.94,.77,.94 L.24,.94 M.53,.2 C.49,.2,.45,.21,.42,.23 C.39,.25,.38,.27,.38,.3 L.38,.45 L.68,.45 L.68,.3 C.68,.27,.67,.25,.64,.23 C.61,.21,.58,.2,.53,.2 M.58,.82 L.58,.66 C.63,.65,.65,.63,.65,.6 C.65,.58,.64,.57,.61,.56 C.58,.55,.56,.54,.52,.54 C.48,.54,.46,.55,.43,.56 C.4,.57,.39,.59,.39,.6 C.39,.63,.41,.64,.46,.66 L.46,.82 L.57,.82",type:0}},"\uE0A3":{type:5,data:{d:"M.7,.4 L.7,.47 L.2,.47 L.2,.03 L.7,.03 L.7,.1 L.355,.1 L.355,.4 L.705,.4 M.7,.5 L.86,.5 L.86,.95 L.69,.95 L.44,.66 L.46,.86 L.46,.95 L.3,.95 L.3,.49 L.46,.49 L.71,.78 L.69,.565 L.69,.5",type:0}},"\uE0B0":{type:5,data:{d:"M0,0 L1,.5 L0,1",type:0,rightPadding:2}},"\uE0B1":{type:5,data:{d:"M-1,-.5 L1,.5 L-1,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0B2":{type:5,data:{d:"M1,0 L0,.5 L1,1",type:0,leftPadding:2}},"\uE0B3":{type:5,data:{d:"M2,-.5 L0,.5 L2,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0B4":{type:5,data:{d:"M0,0 L0,1 C0.552,1,1,0.776,1,.5 C1,0.224,0.552,0,0,0",type:0,rightPadding:1}},"\uE0B5":{type:5,data:{d:"M.2,1 C.422,1,.8,.826,.78,.5 C.8,.174,0.422,0,.2,0",type:1,rightPadding:1}},"\uE0B6":{type:5,data:{d:"M1,0 L1,1 C0.448,1,0,0.776,0,.5 C0,0.224,0.448,0,1,0",type:0,leftPadding:1}},"\uE0B7":{type:5,data:{d:"M.8,1 C0.578,1,0.2,.826,.22,.5 C0.2,0.174,0.578,0,0.8,0",type:1,leftPadding:1}},"\uE0B8":{type:5,data:{d:"M-.5,-.5 L1.5,1.5 L-.5,1.5",type:0}},"\uE0B9":{type:5,data:{d:"M-.5,-.5 L1.5,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0BA":{type:5,data:{d:"M1.5,-.5 L-.5,1.5 L1.5,1.5",type:0}},"\uE0BB":{type:5,data:{d:"M1.5,-.5 L-.5,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0BC":{type:5,data:{d:"M1.5,-.5 L-.5,1.5 L-.5,-.5",type:0}},"\uE0BD":{type:5,data:{d:"M1.5,-.5 L-.5,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0BE":{type:5,data:{d:"M-.5,-.5 L1.5,1.5 L1.5,-.5",type:0}},"\uE0BF":{type:5,data:{d:"M-.5,-.5 L1.5,1.5",type:1,leftPadding:1,rightPadding:1}},"\uE0C0":{type:5,data:{d:"M0.8069,0.6075 Q0.7991,0.612,0.7815,0.6218 T0.7542,0.6369 T0.7282,0.6508 T0.7016,0.6644 T0.6778,0.6758 T0.6551,0.6854 T0.637,0.6911 T0.622,0.6936 Q0.6186,0.6936,0.6128,0.6942 T0.6018,0.6952 T0.5894,0.6956 T0.5757,0.6952 T0.561,0.693 T0.5451,0.6879 Q0.5342,0.6834,0.5193,0.6756 T0.4925,0.6614 T0.4673,0.6485 T0.4436,0.6389 T0.4239,0.6363 T0.4089,0.6422 Q0.4045,0.6467,0.3958,0.6554 T0.3843,0.6669 T0.3748,0.6746 T0.3613,0.683 T0.3442,0.6903 L0.3499,0.6956 Q0.3584,0.7042,0.3679,0.7177 T0.3836,0.7403 T0.4019,0.7583 T0.4295,0.7703 Q0.4688,0.7785,0.5203,0.7605 Q0.4902,0.7817,0.449,0.7911 T0.3696,0.8001 Q0.3567,0.7997,0.341,0.7942 T0.3111,0.7813 T0.2805,0.766 T0.2493,0.753 T0.218,0.7472 T0.187,0.754 Q0.1762,0.7589,0.1653,0.7681 T0.1453,0.7895 T0.1308,0.818 T0.1264,0.8507 L0.1264,0.858 Q0.1453,0.8462,0.1607,0.8433 T0.1899,0.8452 T0.2226,0.8625 Q0.2344,0.8707,0.2485,0.8752 T0.2813,0.8831 T0.3089,0.889 Q0.2981,0.8915,0.2846,0.8956 T0.2603,0.9037 T0.2368,0.9115 T0.2129,0.9174 T0.1894,0.9194 T0.1653,0.9155 Q0.1504,0.9115,0.1328,0.9196 T0.0986,0.9421 T0.0655,0.9708 T0.0317,0.9943 T0,1 Q0.001,0.94,0.0017,0.6508 T0.0024,0.2322 Q0.002,0.2109,0.0007,0.1379 T0,0.0249 Q0.0058,0.0253,0.009,0.0257 T0.0156,0.0288 T0.0203,0.0333 T0.0264,0.0422 T0.0349,0.0539 Q0.044,0.0657,0.0542,0.072 T0.0752,0.0789 T0.096,0.0775 T0.1175,0.0694 T0.1379,0.0573 T0.1579,0.0432 Q0.2141,0,0.2673,0.0318 Q0.2588,0.0318,0.2517,0.033 T0.239,0.0361 T0.2276,0.0424 T0.218,0.0504 T0.2085,0.0612 T0.1997,0.0732 T0.1899,0.0875 T0.1795,0.1028 Q0.1748,0.1093,0.1507,0.1234 T0.1186,0.1448 Q0.0999,0.1612,0.1108,0.1783 Q0.1162,0.1877,0.1238,0.1928 T0.1404,0.1979 T0.158,0.1967 T0.1775,0.1895 T0.1963,0.1791 T0.2151,0.1663 T0.2314,0.1534 T0.2458,0.141 T0.2561,0.1322 Q0.2815,0.1106,0.3017,0.101 T0.344,0.0926 T0.3919,0.1077 Q0.4099,0.1175,0.4265,0.1206 T0.4588,0.1202 T0.488,0.1098 T0.5176,0.0914 Q0.5071,0.1032,0.4963,0.1122 T0.4722,0.1285 T0.4497,0.1401 T0.4223,0.1518 T0.3943,0.1636 Q0.374,0.1726,0.3623,0.1863 T0.3482,0.2162 Q0.3445,0.2403,0.3608,0.2605 T0.4072,0.2876 Q0.4194,0.2909,0.4326,0.2899 T0.457,0.2856 T0.4805,0.2764 T0.5032,0.264 T0.5256,0.2497 T0.5478,0.2352 T0.5698,0.2222 T0.5921,0.2118 Q0.6982,0.173,0.81,0.2436 Q0.833,0.2583,0.8496,0.2674 T0.887,0.2846 T0.925,0.294 T0.9617,0.2911 T1,0.2746 Q0.9817,0.2946,0.96,0.3056 T0.9175,0.3191 T0.8731,0.3209 T0.8277,0.3164 T0.7818,0.3109 T0.7359,0.3101 T0.6907,0.3197 T0.647,0.3448 Q0.6443,0.3472,0.6333,0.3562 T0.6194,0.3674 T0.6076,0.3766 T0.594,0.386 T0.5815,0.3931 T0.5661,0.4007 T0.5501,0.4064 L0.5556,0.4121 Q0.5627,0.4198,0.5722,0.4251 T0.5926,0.4337 T0.6131,0.439 T0.6343,0.4431 T0.6521,0.4468 Q0.6762,0.4529,0.7056,0.4463 Q0.6772,0.4623,0.6543,0.471 T0.604,0.4814 Q0.5962,0.4818,0.5815,0.4825 T0.5591,0.4835 T0.5393,0.4857 T0.519,0.4908 T0.5007,0.4996 T0.4812,0.5141 T0.4627,0.5353 L0.4549,0.5451 L0.4661,0.543 Q0.4759,0.541,0.4909,0.55 T0.5315,0.5796 T0.5684,0.6083 Q0.5799,0.6161,0.5915,0.6212 T0.6181,0.6308 L0.6331,0.6353 Q0.6514,0.6418,0.7004,0.633 T0.8069,0.6075 Z",type:0}},"\uE0C1":{type:5,data:{d:"M0.011,0.0469 Q0.0152,0.0412,0.02,0.0361 T0.0292,0.0281 T0.0365,0.0253 Q0.0426,0.0257,0.0461,0.0263 T0.0534,0.03 T0.0582,0.0345 T0.0645,0.0434 T0.0723,0.0546 Q0.0807,0.0653,0.0897,0.0712 T0.1081,0.0775 T0.1255,0.0765 T0.1438,0.0695 T0.1605,0.0593 T0.1772,0.0473 Q0.2388,0,0.2927,0.0326 L0.2614,0.0767 L0.2581,0.0767 Q0.2494,0.0767,0.2444,0.0773 T0.2359,0.0789 T0.2291,0.0842 T0.2233,0.0922 T0.2146,0.1054 T0.2026,0.1236 Q0.1943,0.1354,0.1843,0.1444 T0.1675,0.1574 T0.1526,0.1654 T0.1429,0.1701 Q0.1436,0.1717,0.1446,0.1733 Q0.1504,0.1823,0.1581,0.1866 T0.1733,0.1915 T0.1909,0.1884 T0.2085,0.1809 T0.2265,0.169 T0.2427,0.1564 T0.2575,0.1436 T0.2688,0.1338 Q0.2969,0.1101,0.3195,0.0995 T0.3643,0.0901 T0.4114,0.1048 Q0.4279,0.1138,0.4426,0.1168 T0.4705,0.117 T0.4945,0.1089 T0.5186,0.0942 L0.5211,0.0926 L0.5289,0.0922 Q0.5411,0.095,0.5189,0.1203 Q0.505,0.1358,0.4913,0.1474 T0.4634,0.167 T0.4389,0.1796 T0.4121,0.1909 T0.3866,0.2011 Q0.3782,0.2047,0.3727,0.2092 Q0.3717,0.2117,0.3714,0.2141 Q0.3695,0.2263,0.3751,0.2388 T0.394,0.2616 T0.4253,0.2761 Q0.4398,0.2785,0.4513,0.2779 T0.4756,0.2724 T0.4987,0.2616 T0.5216,0.2476 T0.5453,0.2321 T0.5703,0.217 T0.5976,0.2043 Q0.7015,0.166,0.8099,0.2345 Q0.8361,0.2512,0.8572,0.2616 T0.9006,0.2779 T0.9432,0.281 T0.9819,0.2663 L0.9887,0.2671 Q1,0.272,0.9768,0.2969 Q0.9558,0.3193,0.9319,0.333 T0.8858,0.3513 T0.8391,0.3569 T0.793,0.3546 T0.7485,0.3497 T0.7065,0.3473 T0.6681,0.3522 T0.6344,0.3699 Q0.5963,0.4005,0.5847,0.4082 Q0.595,0.4139,0.6079,0.4174 T0.6367,0.4237 T0.6586,0.4278 Q0.6793,0.4331,0.7044,0.4278 Q0.7057,0.4278,0.707,0.4274 Q0.7067,0.429,0.7062,0.4313 T0.7036,0.4398 T0.6993,0.4513 T0.6931,0.4619 T0.6851,0.4698 Q0.6573,0.4857,0.6336,0.4947 T0.5831,0.5053 Q0.577,0.5057,0.5615,0.5065 T0.5394,0.508 T0.5221,0.51 T0.5042,0.5139 T0.4905,0.5204 Q0.5008,0.5232,0.515,0.5328 T0.549,0.5585 T0.5799,0.5824 Q0.5905,0.5897,0.6013,0.5946 T0.6262,0.6036 T0.6409,0.6081 Q0.6567,0.6134,0.7035,0.605 T0.8028,0.5816 L0.7974,0.5922 T0.7867,0.6134 L0.7812,0.624 Q0.7799,0.6248,0.7786,0.6252 Q0.7709,0.6297,0.7573,0.6372 T0.7346,0.6499 T0.7123,0.6621 T0.6897,0.6741 T0.6686,0.6847 T0.648,0.6941 T0.6297,0.7013 T0.6129,0.7062 T0.5995,0.7076 Q0.5992,0.7076,0.5831,0.7092 T0.5529,0.7092 T0.525,0.7019 Q0.5105,0.6958,0.4824,0.6811 T0.4356,0.6586 T0.4079,0.6533 Q0.3872,0.6741,0.3827,0.6782 Q0.3872,0.6835,0.3934,0.6929 T0.4037,0.7078 T0.4142,0.7198 T0.4284,0.7304 T0.4466,0.7365 Q0.4824,0.7443,0.5292,0.728 L0.5292,0.7294 T0.529,0.7333 T0.5284,0.7392 T0.5266,0.7463 T0.5236,0.7539 T0.5186,0.7612 T0.5111,0.7679 Q0.5086,0.77,0.5056,0.7716 Q0.4466,0.8104,0.3591,0.8091 Q0.344,0.8091,0.3246,0.802 T0.2893,0.7863 T0.2543,0.77 T0.2206,0.76 T0.1894,0.7643 Q0.1804,0.7684,0.1733,0.7753 Q0.1591,0.7892,0.1601,0.8169 Q0.1784,0.8067,0.1938,0.8053 T0.2212,0.8087 T0.2507,0.825 Q0.2614,0.8324,0.2744,0.8365 T0.3053,0.844 T0.332,0.8499 L0.303,0.894 L0.2998,0.8948 Q0.2904,0.8968,0.278,0.9009 T0.2554,0.9086 T0.233,0.9158 T0.2099,0.9213 T0.1868,0.9229 T0.1633,0.9192 Q0.1517,0.916,0.1367,0.9241 T0.1065,0.9462 T0.0753,0.9737 T0.041,0.9955 T0.0061,1 Q0,0.9984,0.0068,0.9845 Q0.009,0.9804,0.0123,0.9755 Q0.0187,0.9666,0.0261,0.9606 T0.0374,0.9555 Q0.0481,0.958,0.0629,0.949 T0.0931,0.9262 T0.1247,0.8987 T0.1597,0.8777 T0.1949,0.8752 Q0.213,0.8805,0.2343,0.8772 Q0.2249,0.8736,0.2172,0.8683 Q0.1914,0.8511,0.1738,0.8497 T0.1349,0.8617 Q0.1304,0.865,0.1273,0.8646 T0.1242,0.8605 L0.1239,0.8536 Q0.1226,0.8295,0.1354,0.8016 T0.1723,0.7496 Q0.1914,0.7308,0.2104,0.7219 Q0.2259,0.7145,0.2425,0.7141 T0.273,0.7182 T0.3022,0.7296 T0.3301,0.7439 T0.3569,0.7571 T0.3821,0.7643 Q0.373,0.7561,0.3598,0.7367 T0.3382,0.7088 L0.3327,0.7035 Q0.3282,0.699,0.3353,0.6884 T0.3517,0.6692 L0.3611,0.6607 Q0.3711,0.657,0.3751,0.6554 T0.3837,0.6507 T0.3898,0.6458 T0.3979,0.637 T0.4111,0.6236 Q0.4172,0.6175,0.4234,0.6138 Q0.4327,0.6081,0.4439,0.6077 T0.4655,0.6105 T0.4884,0.6201 T0.5113,0.633 T0.5347,0.6468 T0.5573,0.6578 Q0.5705,0.6635,0.5833,0.665 T0.6112,0.665 T0.6286,0.6635 Q0.6421,0.6631,0.6718,0.6501 Q0.626,0.6578,0.6089,0.6517 Q0.6063,0.6509,0.6002,0.6491 T0.5884,0.6454 T0.5757,0.6409 T0.561,0.6344 T0.5466,0.6256 Q0.536,0.6183,0.5108,0.5989 T0.4722,0.5712 T0.4527,0.564 L0.4418,0.5661 Q0.4308,0.5681,0.4366,0.5563 Q0.4401,0.5485,0.4476,0.5392 L0.455,0.5298 Q0.4631,0.5188,0.4714,0.51 T0.4866,0.4947 T0.5021,0.4831 T0.516,0.4749 T0.53,0.4694 T0.5428,0.4657 T0.5558,0.4637 T0.5674,0.4629 T0.5795,0.4625 Q0.5489,0.4543,0.534,0.4384 L0.5286,0.4327 Q0.5244,0.4282,0.5318,0.4174 T0.5486,0.398 L0.5579,0.3899 Q0.567,0.387,0.5749,0.3834 T0.5878,0.3772 T0.6012,0.3687 T0.6126,0.3603 T0.6268,0.3487 T0.6421,0.3361 Q0.6567,0.3242,0.6712,0.3159 T0.7009,0.3034 T0.7277,0.2973 T0.7556,0.2961 T0.7809,0.2977 T0.8074,0.301 Q0.8096,0.3014,0.8109,0.3016 T0.8143,0.302 T0.818,0.3026 Q0.8012,0.2936,0.7767,0.2781 Q0.6718,0.2117,0.5744,0.2476 Q0.5637,0.2516,0.5492,0.2604 T0.5218,0.2779 T0.4923,0.2965 T0.461,0.3124 T0.4282,0.3216 T0.394,0.3206 Q0.3637,0.3136,0.3474,0.2936 T0.3353,0.2459 Q0.3385,0.2247,0.355,0.2023 Q0.3646,0.1892,0.3763,0.179 Q0.3898,0.1672,0.4063,0.1595 Q0.3927,0.1562,0.3785,0.1485 Q0.3604,0.1387,0.3453,0.1354 T0.3161,0.1354 T0.2899,0.1458 T0.2627,0.166 Q0.262,0.1664,0.254,0.1733 T0.2414,0.1841 T0.2267,0.196 T0.2094,0.2086 T0.1915,0.2196 T0.1725,0.2288 T0.1546,0.2337 T0.1373,0.2343 T0.1223,0.228 T0.1097,0.2145 Q0.0962,0.1929,0.1258,0.1582 Q0.131,0.1517,0.1371,0.1464 Q0.1462,0.1387,0.156,0.1321 T0.1752,0.1205 T0.1878,0.1134 Q0.1891,0.1117,0.1947,0.103 T0.2035,0.0899 T0.2125,0.0781 T0.2243,0.064 Q0.1949,0.0616,0.1672,0.0828 Q0.153,0.0934,0.1412,0.1009 T0.1146,0.1146 T0.0873,0.1213 T0.0616,0.116 T0.0374,0.0962 Q0.0339,0.0909,0.0295,0.0846 T0.024,0.0767 T0.0202,0.0728 T0.0148,0.0704 T0.0068,0.0697 Q0.0003,0.0693,0.0058,0.0567 Q0.0077,0.0522,0.011,0.0469 Z",type:0}},"\uE0C2":{type:5,data:{d:"M0.1934,0.6075 Q0.2012,0.612,0.2188,0.6218 T0.2459,0.6369 T0.2718,0.6508 T0.2983,0.6644 T0.322,0.6758 T0.3447,0.6854 T0.363,0.6911 T0.3783,0.6936 Q0.3796,0.6936,0.396,0.6952 T0.4265,0.6952 T0.4548,0.6879 Q0.4656,0.6834,0.4805,0.6756 T0.5073,0.6614 T0.5327,0.6485 T0.5564,0.6389 T0.5759,0.6363 T0.5909,0.6422 Q0.5953,0.6467,0.604,0.6554 T0.6155,0.6669 T0.6251,0.6746 T0.6387,0.683 T0.6556,0.6903 L0.6498,0.6956 Q0.6414,0.7042,0.6319,0.7177 T0.6162,0.7403 T0.5979,0.7583 T0.5703,0.7703 Q0.5313,0.7785,0.4799,0.7605 Q0.5097,0.7817,0.5508,0.7911 T0.6302,0.8001 Q0.6431,0.7997,0.659,0.7942 T0.6888,0.7813 T0.7194,0.766 T0.7506,0.753 T0.7819,0.7472 T0.8131,0.754 Q0.8239,0.7589,0.8346,0.7681 T0.8544,0.7895 T0.8689,0.818 T0.8737,0.8507 L0.8733,0.858 Q0.8591,0.849,0.8474,0.845 T0.8242,0.8421 T0.8021,0.8482 T0.7772,0.8625 Q0.7653,0.8707,0.7513,0.8752 T0.7184,0.8831 T0.6908,0.889 Q0.7017,0.8915,0.7152,0.8956 T0.7396,0.9037 T0.7633,0.9115 T0.7872,0.9174 T0.8107,0.9194 T0.8347,0.9155 Q0.8493,0.9115,0.8671,0.9196 T0.9015,0.9421 T0.9345,0.9708 T0.9682,0.9943 T0.9997,1 Q0.999,0.94,0.9983,0.6508 T0.9976,0.2322 Q0.9976,0.2109,0.9992,0.1379 T1,0.0249 Q0.9949,0.0249,0.9917,0.0257 T0.9863,0.0273 T0.9817,0.0308 T0.9776,0.0357 T0.9721,0.0437 T0.9651,0.0539 Q0.956,0.0657,0.9456,0.072 T0.9247,0.0789 T0.904,0.0775 T0.8823,0.0694 T0.862,0.0573 T0.8422,0.0432 Q0.7856,0,0.7328,0.0318 Q0.7392,0.0318,0.7452,0.0324 T0.756,0.0345 T0.7657,0.0386 T0.7741,0.0437 T0.7821,0.0506 T0.7894,0.0588 T0.7966,0.0683 T0.8039,0.0787 T0.8119,0.0904 T0.8202,0.1028 Q0.8249,0.1093,0.849,0.1234 T0.8811,0.1448 Q0.8998,0.1612,0.8893,0.1783 Q0.8835,0.1877,0.8759,0.1928 T0.8593,0.1979 T0.8417,0.1967 T0.8222,0.1895 T0.8034,0.1791 T0.7848,0.1663 T0.7687,0.1534 T0.7543,0.141 T0.744,0.1322 Q0.7186,0.1106,0.6984,0.101 T0.6559,0.0926 T0.6082,0.1077 Q0.5899,0.1175,0.5733,0.1206 T0.5411,0.1202 T0.5122,0.1098 T0.4822,0.0914 Q0.4927,0.1032,0.5036,0.1122 T0.5276,0.1285 T0.5503,0.1401 T0.5777,0.1518 T0.6055,0.1636 Q0.6258,0.1726,0.6375,0.1863 T0.6519,0.2162 Q0.6556,0.2403,0.6392,0.2605 T0.5926,0.2876 Q0.5804,0.2909,0.5672,0.2899 T0.5428,0.2856 T0.5193,0.2764 T0.4966,0.264 T0.4744,0.2497 T0.4523,0.2352 T0.4301,0.2222 T0.4077,0.2118 Q0.3021,0.173,0.1903,0.2436 Q0.1669,0.2583,0.1504,0.2674 T0.1129,0.2846 T0.075,0.294 T0.0384,0.2911 T0,0.2746 Q0.021,0.297,0.0459,0.3082 T0.0953,0.3207 T0.146,0.3193 T0.1988,0.3131 T0.2508,0.3095 T0.3029,0.3176 T0.3529,0.3448 Q0.3566,0.348,0.3652,0.355 T0.3771,0.3645 T0.3877,0.3731 T0.3993,0.3815 T0.4103,0.3884 T0.4226,0.3953 T0.4352,0.4009 T0.4497,0.4064 L0.4443,0.4121 Q0.4372,0.4198,0.4277,0.4251 T0.4072,0.4337 T0.3867,0.439 T0.3656,0.4431 T0.3481,0.4468 Q0.3241,0.4529,0.2943,0.4463 Q0.3227,0.4623,0.3458,0.471 T0.3959,0.4814 Q0.404,0.4818,0.4187,0.4825 T0.4409,0.4835 T0.4605,0.4857 T0.4809,0.4908 T0.4992,0.4996 T0.5186,0.5141 T0.5371,0.5353 L0.5449,0.5451 L0.5337,0.543 Q0.5242,0.541,0.5091,0.55 T0.4683,0.5796 T0.4314,0.6083 Q0.4203,0.6161,0.4086,0.6212 T0.382,0.6308 T0.3667,0.6353 Q0.3485,0.6418,0.2995,0.633 T0.1934,0.6075 Z",type:0}},"\uE0C3":{type:5,data:{d:"M0.989,0.0469 Q0.9829,0.0379,0.9753,0.0316 T0.9635,0.0253 Q0.9574,0.0257,0.9539,0.0263 T0.9466,0.03 T0.9418,0.0345 T0.9355,0.0434 T0.9277,0.0546 Q0.9193,0.0653,0.9103,0.0712 T0.8919,0.0775 T0.8745,0.0765 T0.8564,0.0695 T0.8396,0.0593 T0.8228,0.0473 Q0.7612,0,0.7073,0.0326 L0.7386,0.0767 L0.7419,0.0767 Q0.7506,0.0767,0.7556,0.0773 T0.7641,0.0789 T0.7709,0.0842 T0.7767,0.0922 T0.7854,0.1054 T0.7974,0.1236 Q0.8057,0.1354,0.8157,0.1444 T0.8325,0.1574 T0.8474,0.1654 T0.8571,0.1701 Q0.8564,0.1717,0.8554,0.1733 Q0.8503,0.1815,0.844,0.186 T0.8301,0.1909 T0.8153,0.1903 T0.7993,0.1845 T0.7836,0.1758 T0.768,0.1648 T0.754,0.1535 T0.741,0.1425 T0.7312,0.1338 Q0.7031,0.1101,0.6805,0.0995 T0.6357,0.0901 T0.5886,0.1048 Q0.5721,0.1138,0.5574,0.1168 T0.5295,0.117 T0.5055,0.1089 T0.4814,0.0942 L0.4789,0.0926 L0.4711,0.0922 Q0.4589,0.095,0.4811,0.1203 Q0.495,0.1358,0.5087,0.1474 T0.5366,0.167 T0.5611,0.1796 T0.5879,0.1909 T0.6134,0.2011 Q0.6218,0.2047,0.6273,0.2092 Q0.6283,0.2117,0.6286,0.2141 Q0.6305,0.2263,0.6249,0.2388 T0.606,0.2616 T0.5747,0.2761 Q0.5602,0.2785,0.5487,0.2779 T0.5245,0.2724 T0.5015,0.2616 T0.4784,0.2476 T0.4547,0.2321 T0.4297,0.217 T0.4024,0.2043 Q0.2985,0.166,0.1901,0.2345 Q0.1694,0.248,0.1523,0.2569 T0.1165,0.2726 T0.0818,0.2812 T0.0494,0.2796 T0.0181,0.2663 L0.0116,0.2671 Q0,0.272,0.0232,0.2969 Q0.0468,0.3222,0.0742,0.3365 T0.1278,0.3542 T0.1807,0.3564 T0.233,0.352 T0.2815,0.3473 T0.3269,0.3509 T0.3656,0.3699 Q0.4037,0.4005,0.4153,0.4082 Q0.405,0.4139,0.3921,0.4174 T0.3633,0.4237 T0.3414,0.4278 Q0.3207,0.4331,0.2956,0.4278 Q0.2943,0.4278,0.293,0.4274 Q0.2933,0.429,0.2938,0.4313 T0.2964,0.4398 T0.3007,0.4513 T0.3069,0.4619 T0.3149,0.4698 Q0.3427,0.4857,0.3664,0.4947 T0.4169,0.5053 Q0.423,0.5057,0.4385,0.5065 T0.4606,0.508 T0.4779,0.51 T0.4958,0.5139 T0.5095,0.5204 Q0.4992,0.5232,0.485,0.5328 T0.451,0.5585 T0.4201,0.5824 Q0.4095,0.5897,0.3987,0.5946 T0.3738,0.6036 T0.3591,0.6081 Q0.3433,0.6134,0.2965,0.605 T0.1972,0.5816 L0.2026,0.5922 T0.2133,0.6134 L0.2188,0.624 Q0.2201,0.6248,0.2214,0.6252 Q0.2291,0.6297,0.2486,0.6405 T0.2786,0.657 T0.3066,0.6721 T0.3353,0.6866 T0.3598,0.6972 T0.383,0.7051 T0.4005,0.7076 Q0.4008,0.7076,0.4169,0.7092 T0.4471,0.7092 T0.475,0.7019 Q0.4895,0.6958,0.5176,0.6811 T0.5644,0.6586 T0.5921,0.6533 Q0.6128,0.6741,0.6173,0.6782 Q0.6131,0.6835,0.6068,0.6929 T0.5963,0.7078 T0.5858,0.7198 T0.5716,0.7304 T0.5534,0.7365 Q0.5179,0.7443,0.4708,0.728 L0.4708,0.7294 T0.471,0.7333 T0.4716,0.7392 T0.4734,0.7463 T0.4764,0.7539 T0.4814,0.7612 T0.4889,0.7679 Q0.4914,0.77,0.4944,0.7716 Q0.5534,0.8104,0.6409,0.8091 Q0.6521,0.8091,0.6654,0.8053 T0.6907,0.7959 T0.7157,0.7838 T0.741,0.772 T0.7652,0.7631 T0.7888,0.7594 T0.8106,0.7643 Q0.8196,0.7684,0.8267,0.7753 Q0.8409,0.7892,0.8399,0.8169 Q0.8216,0.8067,0.8062,0.8053 T0.7788,0.8087 T0.7493,0.825 Q0.7386,0.8324,0.7256,0.8365 T0.6947,0.844 T0.668,0.8499 L0.697,0.894 L0.7002,0.8948 Q0.7099,0.8968,0.7222,0.9009 T0.7446,0.9086 T0.767,0.9158 T0.7901,0.9213 T0.8132,0.9229 T0.8367,0.9192 Q0.8483,0.916,0.8633,0.9241 T0.8937,0.9462 T0.9248,0.9737 T0.959,0.9955 T0.9939,1 Q1,0.9984,0.9932,0.9845 Q0.991,0.9804,0.9877,0.9755 Q0.9813,0.9666,0.9739,0.9606 T0.9626,0.9555 Q0.9519,0.958,0.9372,0.949 T0.9071,0.9262 T0.8753,0.8987 T0.8403,0.8777 T0.8051,0.8752 Q0.787,0.8805,0.7657,0.8772 Q0.7751,0.8736,0.7828,0.8683 Q0.8086,0.8511,0.8262,0.8497 T0.8651,0.8617 Q0.8696,0.865,0.8727,0.8646 T0.8758,0.8605 L0.8761,0.8536 Q0.8774,0.8295,0.8646,0.8016 T0.8277,0.7496 Q0.8086,0.7308,0.7896,0.7219 Q0.7741,0.7145,0.7575,0.7141 T0.727,0.7182 T0.6978,0.7296 T0.6699,0.7439 T0.6433,0.7571 T0.6179,0.7643 Q0.627,0.7561,0.6402,0.7367 T0.6618,0.7088 L0.6673,0.7035 Q0.6718,0.699,0.6647,0.6884 T0.6483,0.6692 L0.6389,0.6607 Q0.6289,0.657,0.6249,0.6554 T0.6163,0.6507 T0.6102,0.6458 T0.6021,0.637 T0.5889,0.6236 Q0.5828,0.6175,0.5766,0.6138 Q0.5673,0.6081,0.5561,0.6077 T0.5345,0.6105 T0.5116,0.6201 T0.4887,0.633 T0.4653,0.6468 T0.4427,0.6578 Q0.4295,0.6635,0.4167,0.665 T0.3888,0.665 T0.3714,0.6635 Q0.3579,0.6631,0.3282,0.6501 Q0.374,0.6578,0.3911,0.6517 Q0.3937,0.6509,0.4024,0.6482 T0.4179,0.6434 T0.4348,0.6364 T0.4534,0.6256 Q0.464,0.6183,0.4892,0.5989 T0.5278,0.5712 T0.5476,0.564 L0.5582,0.5661 Q0.5692,0.5681,0.5634,0.5563 Q0.5599,0.5485,0.5524,0.5392 L0.545,0.5298 Q0.5369,0.5188,0.5286,0.51 T0.5134,0.4947 T0.4979,0.4831 T0.484,0.4749 T0.47,0.4694 T0.4572,0.4657 T0.4442,0.4637 T0.4326,0.4629 T0.4205,0.4625 Q0.4511,0.4543,0.466,0.4384 L0.4714,0.4327 Q0.4795,0.4237,0.4469,0.394 L0.4421,0.3899 Q0.433,0.387,0.4251,0.3834 T0.4122,0.3772 T0.3988,0.3687 T0.3874,0.3603 T0.3732,0.3487 T0.3579,0.3361 Q0.3433,0.3242,0.3288,0.3159 T0.2993,0.3034 T0.2725,0.2973 T0.2446,0.2961 T0.2193,0.2977 T0.1926,0.301 Q0.1855,0.3022,0.182,0.3026 Q0.1991,0.2936,0.2233,0.2781 Q0.3282,0.2117,0.4256,0.2476 Q0.4363,0.2516,0.451,0.2604 T0.4784,0.2779 T0.5077,0.2965 T0.539,0.3124 T0.5718,0.3216 T0.606,0.3206 Q0.6363,0.3136,0.6526,0.2936 T0.6647,0.2459 Q0.6615,0.2247,0.645,0.2023 Q0.6354,0.1892,0.6237,0.179 Q0.6102,0.1672,0.5937,0.1595 Q0.6073,0.1562,0.6215,0.1485 Q0.6396,0.1387,0.6547,0.1354 T0.6839,0.1354 T0.7101,0.1458 T0.7373,0.166 Q0.738,0.1664,0.746,0.1733 T0.7586,0.1841 T0.7733,0.196 T0.7907,0.2086 T0.8086,0.2196 T0.8275,0.2288 T0.8454,0.2337 T0.8627,0.2343 T0.8777,0.228 T0.8903,0.2145 Q0.9038,0.1929,0.8742,0.1582 Q0.869,0.1517,0.8629,0.1464 Q0.8538,0.1387,0.844,0.1321 T0.8248,0.1205 T0.8122,0.1134 Q0.8109,0.1117,0.8053,0.103 T0.7965,0.0899 T0.7875,0.0781 T0.7757,0.064 Q0.8051,0.0616,0.8328,0.0828 Q0.847,0.0934,0.8588,0.1009 T0.8854,0.1146 T0.9127,0.1213 T0.9384,0.116 T0.9626,0.0962 Q0.9664,0.0909,0.9706,0.0846 T0.976,0.0767 T0.9798,0.0728 T0.9852,0.0704 T0.9932,0.0697 Q0.9997,0.0693,0.9942,0.0567 Q0.9923,0.0522,0.989,0.0469 Z",type:0}},"\uE0C4":{type:5,data:{d:"M0.4116,0.0126 L0.4116,0.0776 L0.4871,0.0776 L0.4871,0.0126 L0.4116,0.0126 Z M0.4043,0 L0.4944,0 Q0.4973,0,0.4995,0.0021 T0.5017,0.0063 L0.5017,0.0839 Q0.5017,0.0864,0.4993,0.0883 T0.4944,0.0902 L0.4043,0.0902 Q0.4014,0.0902,0.3992,0.0881 T0.397,0.0839 L0.397,0.0063 Q0.397,0.0038,0.3994,0.0019 T0.4043,0 Z M0.4116,0.0126 L0.4116,0.0776 L0.4871,0.0776 L0.4871,0.0126 L0.4116,0.0126 Z M0.4043,0 L0.4944,0 Q0.4973,0,0.4995,0.0021 T0.5017,0.0063 L0.5017,0.0839 Q0.5017,0.0864,0.4993,0.0883 T0.4944,0.0902 L0.4043,0.0902 Q0.4014,0.0902,0.3992,0.0881 T0.397,0.0839 L0.397,0.0063 Q0.397,0.0038,0.3994,0.0019 T0.4043,0 Z M0.4116,0.0126 L0.4116,0.0776 L0.4871,0.0776 L0.4871,0.0126 L0.4116,0.0126 Z M0.4043,0 L0.4944,0 Q0.4973,0,0.4995,0.0021 T0.5017,0.0063 L0.5017,0.0839 Q0.5017,0.0864,0.4993,0.0883 T0.4944,0.0902 L0.4043,0.0902 Q0.4014,0.0902,0.3992,0.0881 T0.397,0.0839 L0.397,0.0063 Q0.397,0.0038,0.3994,0.0019 T0.4043,0 Z M0.9099,0.0084 L0.9099,0.0818 L0.9951,0.0818 L0.9951,0.0084 L0.9099,0.0084 Z M0.9075,0.0042 L0.9976,0.0042 Q1,0.0042,1,0.0063 L1,0.0839 Q1,0.086,0.9976,0.086 L0.9075,0.086 Q0.905,0.086,0.905,0.0839 L0.905,0.0063 Q0.905,0.0042,0.9075,0.0042 Z M0.9099,0.0084 L0.9099,0.0818 L0.9951,0.0818 L0.9951,0.0084 L0.9099,0.0084 Z M0.9075,0.0042 L0.9976,0.0042 Q1,0.0042,1,0.0063 L1,0.0839 Q1,0.086,0.9976,0.086 L0.9075,0.086 Q0.905,0.086,0.905,0.0839 L0.905,0.0063 Q0.905,0.0042,0.9075,0.0042 Z M0.9099,0.0084 L0.9099,0.0818 L0.9951,0.0818 L0.9951,0.0084 L0.9099,0.0084 Z M0.9075,0.0042 L0.9976,0.0042 Q1,0.0042,1,0.0063 L1,0.0839 Q1,0.086,0.9976,0.086 L0.9075,0.086 Q0.905,0.086,0.905,0.0839 L0.905,0.0063 Q0.905,0.0042,0.9075,0.0042 Z M0.66,0.0063 L0.7501,0.0063 L0.7501,0.0839 L0.66,0.0839 L0.66,0.0063 Z M0.66,0.0063 L0.7501,0.0063 L0.7501,0.0839 L0.66,0.0839 L0.66,0.0063 Z M0.66,0.0063 L0.7501,0.0063 L0.7501,0.0839 L0.66,0.0839 L0.66,0.0063 Z M0.5309,0.0063 L0.621,0.0063 L0.621,0.0839 L0.5309,0.0839 L0.5309,0.0063 Z M0.5309,0.0063 L0.621,0.0063 L0.621,0.0839 L0.5309,0.0839 L0.5309,0.0063 Z M0.5309,0.0063 L0.621,0.0063 L0.621,0.0839 L0.5309,0.0839 L0.5309,0.0063 Z M0.2689,0.0063 L0.359,0.0063 L0.359,0.0839 L0.2689,0.0839 L0.2689,0.0063 Z M0.2689,0.0063 L0.359,0.0063 L0.359,0.0839 L0.2689,0.0839 L0.2689,0.0063 Z M0.2689,0.0063 L0.359,0.0063 L0.359,0.0839 L0.2689,0.0839 L0.2689,0.0063 Z M0.1374,0.0063 L0.2275,0.0063 L0.2275,0.0839 L0.1374,0.0839 L0.1374,0.0063 Z M0.1374,0.0063 L0.2275,0.0063 L0.2275,0.0839 L0.1374,0.0839 L0.1374,0.0063 Z M0.1374,0.0063 L0.2275,0.0063 L0.2275,0.0839 L0.1374,0.0839 L0.1374,0.0063 Z M0,0.0063 L0.0901,0.0063 L0.0901,0.0839 L0,0.0839 L0,0.0063 Z M0,0.0063 L0.0901,0.0063 L0.0901,0.0839 L0,0.0839 L0,0.0063 Z M0,0.0063 L0.0901,0.0063 L0.0901,0.0839 L0,0.0839 L0,0.0063 Z M0.4087,0.9224 L0.4087,0.9958 L0.4939,0.9958 L0.4939,0.9224 L0.4087,0.9224 Z M0.4062,0.9182 L0.4963,0.9182 Q0.4988,0.9182,0.4988,0.9203 L0.4988,0.9979 Q0.4988,1,0.4963,1 L0.4062,1 Q0.4038,1,0.4038,0.9979 L0.4038,0.9203 Q0.4038,0.9182,0.4062,0.9182 Z M0.4087,0.9224 L0.4087,0.9958 L0.4939,0.9958 L0.4939,0.9224 L0.4087,0.9224 Z M0.4062,0.9182 L0.4963,0.9182 Q0.4988,0.9182,0.4988,0.9203 L0.4988,0.9979 Q0.4988,1,0.4963,1 L0.4062,1 Q0.4038,1,0.4038,0.9979 L0.4038,0.9203 Q0.4038,0.9182,0.4062,0.9182 Z M0.4087,0.9224 L0.4087,0.9958 L0.4939,0.9958 L0.4939,0.9224 L0.4087,0.9224 Z M0.4062,0.9182 L0.4963,0.9182 Q0.4988,0.9182,0.4988,0.9203 L0.4988,0.9979 Q0.4988,1,0.4963,1 L0.4062,1 Q0.4038,1,0.4038,0.9979 L0.4038,0.9203 Q0.4038,0.9182,0.4062,0.9182 Z M0.1374,0.9203 L0.2275,0.9203 L0.2275,0.9979 L0.1374,0.9979 L0.1374,0.9203 Z M0.1374,0.9203 L0.2275,0.9203 L0.2275,0.9979 L0.1374,0.9979 L0.1374,0.9203 Z M0.1374,0.9203 L0.2275,0.9203 L0.2275,0.9979 L0.1374,0.9979 L0.1374,0.9203 Z M0,0.9203 L0.0901,0.9203 L0.0901,0.9979 L0,0.9979 L0,0.9203 Z M0,0.9203 L0.0901,0.9203 L0.0901,0.9979 L0,0.9979 L0,0.9203 Z M0,0.9203 L0.0901,0.9203 L0.0901,0.9979 L0,0.9979 L0,0.9203 Z M0.9099,0.1158 L0.9099,0.1888 L0.9951,0.1888 L0.9951,0.1158 L0.9099,0.1158 Z M0.9075,0.1116 L0.9976,0.1116 Q1,0.1116,1,0.1137 L1,0.1909 Q1,0.193,0.9976,0.193 L0.9075,0.193 Q0.905,0.193,0.905,0.1909 L0.905,0.1137 Q0.905,0.1116,0.9075,0.1116 Z M0.7852,0.6086 L0.7852,0.682 L0.8704,0.682 L0.8704,0.6086 L0.7852,0.6086 Z M0.7828,0.6044 L0.8729,0.6044 Q0.8753,0.6044,0.8753,0.6065 L0.8753,0.6841 Q0.8753,0.6862,0.8729,0.6862 L0.7828,0.6862 Q0.7803,0.6862,0.7803,0.6841 L0.7803,0.6065 Q0.7803,0.6044,0.7828,0.6044 Z M0.66,0.1137 L0.7501,0.1137 L0.7501,0.1909 L0.66,0.1909 L0.66,0.1137 Z M0.6624,0.4102 L0.6624,0.4836 L0.7477,0.4836 L0.7477,0.4102 L0.6624,0.4102 Z M0.66,0.406 L0.7501,0.406 Q0.7526,0.406,0.7526,0.4081 L0.7526,0.4857 Q0.7526,0.4878,0.7501,0.4878 L0.66,0.4878 Q0.6576,0.4878,0.6576,0.4857 L0.6576,0.4081 Q0.6576,0.406,0.66,0.406 Z M0.6624,0.7131 L0.6624,0.7865 L0.7477,0.7865 L0.7477,0.7131 L0.6624,0.7131 Z M0.66,0.7089 L0.7501,0.7089 Q0.7526,0.7089,0.7526,0.711 L0.7526,0.7886 Q0.7526,0.7907,0.7501,0.7907 L0.66,0.7907 Q0.6576,0.7907,0.6576,0.7886 L0.6576,0.711 Q0.6576,0.7089,0.66,0.7089 Z M0.5407,0.2227 L0.5407,0.2836 L0.6113,0.2836 L0.6113,0.2227 L0.5407,0.2227 Z M0.5309,0.206 L0.621,0.206 Q0.623,0.206,0.6249,0.2068 T0.6281,0.2089 T0.6301,0.2116 T0.6308,0.2143 L0.6308,0.2919 Q0.6308,0.2957,0.6276,0.298 T0.621,0.3003 L0.5309,0.3003 Q0.5265,0.3003,0.5239,0.2976 T0.5212,0.2919 L0.5212,0.2143 Q0.5212,0.211,0.5244,0.2085 T0.5309,0.206 Z M0.5407,0.3184 L0.5407,0.3792 L0.6113,0.3792 L0.6113,0.3184 L0.5407,0.3184 Z M0.5309,0.3016 L0.621,0.3016 Q0.6254,0.3016,0.6281,0.3043 T0.6308,0.31 L0.6308,0.3876 Q0.6308,0.3914,0.6276,0.3937 T0.621,0.396 L0.5309,0.396 Q0.5265,0.396,0.5239,0.3932 T0.5212,0.3876 L0.5212,0.31 Q0.5212,0.3062,0.5244,0.3039 T0.5309,0.3016 Z M0.5309,0.4081 L0.621,0.4081 L0.621,0.4857 L0.5309,0.4857 L0.5309,0.4081 Z M0.5309,0.5059 L0.621,0.5059 L0.621,0.5835 L0.5309,0.5835 L0.5309,0.5059 Z M0.5407,0.6149 L0.5407,0.6758 L0.6113,0.6758 L0.6113,0.6149 L0.5407,0.6149 Z M0.5309,0.5982 L0.621,0.5982 Q0.6254,0.5982,0.6281,0.6009 T0.6308,0.6065 L0.6308,0.6841 Q0.6308,0.6879,0.6276,0.6902 T0.621,0.6925 L0.5309,0.6925 Q0.5265,0.6925,0.5239,0.6898 T0.5212,0.6841 L0.5212,0.6065 Q0.5212,0.6028,0.5244,0.6005 T0.5309,0.5982 Z M0.4062,0.1137 L0.4963,0.1137 L0.4963,0.1909 L0.4062,0.1909 L0.4062,0.1137 Z M0.4062,0.2143 L0.4963,0.2143 L0.4963,0.2919 L0.4062,0.2919 L0.4062,0.2143 Z M0.4184,0.4186 L0.4184,0.4753 L0.4842,0.4753 L0.4842,0.4186 L0.4184,0.4186 Z M0.4062,0.3977 L0.4963,0.3977 Q0.5017,0.3977,0.5051,0.401 T0.5085,0.4081 L0.5085,0.4857 Q0.5085,0.4904,0.5046,0.4933 T0.4963,0.4962 L0.4062,0.4962 Q0.4009,0.4962,0.3975,0.4929 T0.3941,0.4857 L0.3941,0.4081 Q0.3941,0.4035,0.398,0.4006 T0.4062,0.3977 Z M0.4062,0.5059 L0.4963,0.5059 L0.4963,0.5835 L0.4062,0.5835 L0.4062,0.5059 Z M0.4087,0.7131 L0.4087,0.7865 L0.4939,0.7865 L0.4939,0.7131 L0.4087,0.7131 Z M0.4062,0.7089 L0.4963,0.7089 Q0.4988,0.7089,0.4988,0.711 L0.4988,0.7886 Q0.4988,0.7907,0.4963,0.7907 L0.4062,0.7907 Q0.4038,0.7907,0.4038,0.7886 L0.4038,0.711 Q0.4038,0.7089,0.4062,0.7089 Z M0.2689,0.1137 L0.359,0.1137 L0.359,0.1909 L0.2689,0.1909 L0.2689,0.1137 Z M0.2689,0.2143 L0.359,0.2143 L0.359,0.2919 L0.2689,0.2919 L0.2689,0.2143 Z M0.2689,0.8154 L0.359,0.8154 L0.359,0.8926 L0.2689,0.8926 L0.2689,0.8154 Z M0.2689,0.31 L0.359,0.31 L0.359,0.3876 L0.2689,0.3876 L0.2689,0.31 Z M0.2689,0.8154 L0.359,0.8154 L0.359,0.8926 L0.2689,0.8926 L0.2689,0.8154 Z M0.2689,0.4081 L0.359,0.4081 L0.359,0.4857 L0.2689,0.4857 L0.2689,0.4081 Z M0.2689,0.5059 L0.359,0.5059 L0.359,0.5835 L0.2689,0.5835 L0.2689,0.5059 Z M0.2689,0.711 L0.359,0.711 L0.359,0.7886 L0.2689,0.7886 L0.2689,0.711 Z M0.2689,0.8154 L0.359,0.8154 L0.359,0.8926 L0.2689,0.8926 L0.2689,0.8154 Z M0.1374,0.1137 L0.2275,0.1137 L0.2275,0.1909 L0.1374,0.1909 L0.1374,0.1137 Z M0.1374,0.2143 L0.2275,0.2143 L0.2275,0.2919 L0.1374,0.2919 L0.1374,0.2143 Z M0.1374,0.8154 L0.2275,0.8154 L0.2275,0.8926 L0.1374,0.8926 L0.1374,0.8154 Z M0.1374,0.31 L0.2275,0.31 L0.2275,0.3876 L0.1374,0.3876 L0.1374,0.31 Z M0.1374,0.8154 L0.2275,0.8154 L0.2275,0.8926 L0.1374,0.8926 L0.1374,0.8154 Z M0.1374,0.4081 L0.2275,0.4081 L0.2275,0.4857 L0.1374,0.4857 L0.1374,0.4081 Z M0.1374,0.5059 L0.2275,0.5059 L0.2275,0.5835 L0.1374,0.5835 L0.1374,0.5059 Z M0.1374,0.6065 L0.2275,0.6065 L0.2275,0.6841 L0.1374,0.6841 L0.1374,0.6065 Z M0.1374,0.711 L0.2275,0.711 L0.2275,0.7886 L0.1374,0.7886 L0.1374,0.711 Z M0.1374,0.8154 L0.2275,0.8154 L0.2275,0.8926 L0.1374,0.8926 L0.1374,0.8154 Z M0,0.1137 L0.0901,0.1137 L0.0901,0.1909 L0,0.1909 L0,0.1137 Z M0,0.2143 L0.0901,0.2143 L0.0901,0.2919 L0,0.2919 L0,0.2143 Z M0,0.8154 L0.0901,0.8154 L0.0901,0.8926 L0,0.8926 L0,0.8154 Z M0,0.31 L0.0901,0.31 L0.0901,0.3876 L0,0.3876 L0,0.31 Z M0,0.8154 L0.0901,0.8154 L0.0901,0.8926 L0,0.8926 L0,0.8154 Z M0,0.4081 L0.0901,0.4081 L0.0901,0.4857 L0,0.4857 L0,0.4081 Z M0,0.5059 L0.0901,0.5059 L0.0901,0.5835 L0,0.5835 L0,0.5059 Z M0,0.6065 L0.0901,0.6065 L0.0901,0.6841 L0,0.6841 L0,0.6065 Z M0,0.711 L0.0901,0.711 L0.0901,0.7886 L0,0.7886 L0,0.711 Z M0,0.8154 L0.0901,0.8154 L0.0901,0.8926 L0,0.8926 L0,0.8154 Z",type:0}},"\uE0C5":{type:5,data:{d:"M0.5884,0.0126 L0.5884,0.0776 L0.5129,0.0776 L0.5129,0.0126 L0.5884,0.0126 Z M0.5957,0 L0.5056,0 Q0.5027,0,0.5005,0.0021 T0.4983,0.0063 L0.4983,0.0839 Q0.4983,0.0864,0.5007,0.0883 T0.5056,0.0902 L0.5957,0.0902 Q0.5986,0.0902,0.6008,0.0881 T0.603,0.0839 L0.603,0.0063 Q0.603,0.0038,0.6006,0.0019 T0.5957,0 Z M0.5884,0.0126 L0.5884,0.0776 L0.5129,0.0776 L0.5129,0.0126 L0.5884,0.0126 Z M0.5957,0 L0.5056,0 Q0.5027,0,0.5005,0.0021 T0.4983,0.0063 L0.4983,0.0839 Q0.4983,0.0864,0.5007,0.0883 T0.5056,0.0902 L0.5957,0.0902 Q0.5986,0.0902,0.6008,0.0881 T0.603,0.0839 L0.603,0.0063 Q0.603,0.0038,0.6006,0.0019 T0.5957,0 Z M0.5884,0.0126 L0.5884,0.0776 L0.5129,0.0776 L0.5129,0.0126 L0.5884,0.0126 Z M0.5957,0 L0.5056,0 Q0.5027,0,0.5005,0.0021 T0.4983,0.0063 L0.4983,0.0839 Q0.4983,0.0864,0.5007,0.0883 T0.5056,0.0902 L0.5957,0.0902 Q0.5986,0.0902,0.6008,0.0881 T0.603,0.0839 L0.603,0.0063 Q0.603,0.0038,0.6006,0.0019 T0.5957,0 Z M0.0901,0.0084 L0.0901,0.0818 L0.0049,0.0818 L0.0049,0.0084 L0.0901,0.0084 Z M0.0925,0.0042 L0.0024,0.0042 Q0,0.0042,0,0.0063 L0,0.0839 Q0,0.086,0.0024,0.086 L0.0925,0.086 Q0.095,0.086,0.095,0.0839 L0.095,0.0063 Q0.095,0.0042,0.0925,0.0042 Z M0.0901,0.0084 L0.0901,0.0818 L0.0049,0.0818 L0.0049,0.0084 L0.0901,0.0084 Z M0.0925,0.0042 L0.0024,0.0042 Q0,0.0042,0,0.0063 L0,0.0839 Q0,0.086,0.0024,0.086 L0.0925,0.086 Q0.095,0.086,0.095,0.0839 L0.095,0.0063 Q0.095,0.0042,0.0925,0.0042 Z M0.0901,0.0084 L0.0901,0.0818 L0.0049,0.0818 L0.0049,0.0084 L0.0901,0.0084 Z M0.0925,0.0042 L0.0024,0.0042 Q0,0.0042,0,0.0063 L0,0.0839 Q0,0.086,0.0024,0.086 L0.0925,0.086 Q0.095,0.086,0.095,0.0839 L0.095,0.0063 Q0.095,0.0042,0.0925,0.0042 Z M0.34,0.0063 L0.2499,0.0063 L0.2499,0.0839 L0.34,0.0839 L0.34,0.0063 Z M0.34,0.0063 L0.2499,0.0063 L0.2499,0.0839 L0.34,0.0839 L0.34,0.0063 Z M0.34,0.0063 L0.2499,0.0063 L0.2499,0.0839 L0.34,0.0839 L0.34,0.0063 Z M0.4691,0.0063 L0.379,0.0063 L0.379,0.0839 L0.4691,0.0839 L0.4691,0.0063 Z M0.4691,0.0063 L0.379,0.0063 L0.379,0.0839 L0.4691,0.0839 L0.4691,0.0063 Z M0.4691,0.0063 L0.379,0.0063 L0.379,0.0839 L0.4691,0.0839 L0.4691,0.0063 Z M0.7311,0.0063 L0.641,0.0063 L0.641,0.0839 L0.7311,0.0839 L0.7311,0.0063 Z M0.7311,0.0063 L0.641,0.0063 L0.641,0.0839 L0.7311,0.0839 L0.7311,0.0063 Z M0.7311,0.0063 L0.641,0.0063 L0.641,0.0839 L0.7311,0.0839 L0.7311,0.0063 Z M0.8626,0.0063 L0.7725,0.0063 L0.7725,0.0839 L0.8626,0.0839 L0.8626,0.0063 Z M0.8626,0.0063 L0.7725,0.0063 L0.7725,0.0839 L0.8626,0.0839 L0.8626,0.0063 Z M0.8626,0.0063 L0.7725,0.0063 L0.7725,0.0839 L0.8626,0.0839 L0.8626,0.0063 Z M1,0.0063 L0.9099,0.0063 L0.9099,0.0839 L1,0.0839 L1,0.0063 Z M1,0.0063 L0.9099,0.0063 L0.9099,0.0839 L1,0.0839 L1,0.0063 Z M1,0.0063 L0.9099,0.0063 L0.9099,0.0839 L1,0.0839 L1,0.0063 Z M0.5913,0.9224 L0.5913,0.9958 L0.5061,0.9958 L0.5061,0.9224 L0.5913,0.9224 Z M0.5938,0.9182 L0.5037,0.9182 Q0.5012,0.9182,0.5012,0.9203 L0.5012,0.9979 Q0.5012,1,0.5037,1 L0.5938,1 Q0.5962,1,0.5962,0.9979 L0.5962,0.9203 Q0.5962,0.9182,0.5938,0.9182 Z M0.5913,0.9224 L0.5913,0.9958 L0.5061,0.9958 L0.5061,0.9224 L0.5913,0.9224 Z M0.5938,0.9182 L0.5037,0.9182 Q0.5012,0.9182,0.5012,0.9203 L0.5012,0.9979 Q0.5012,1,0.5037,1 L0.5938,1 Q0.5962,1,0.5962,0.9979 L0.5962,0.9203 Q0.5962,0.9182,0.5938,0.9182 Z M0.5913,0.9224 L0.5913,0.9958 L0.5061,0.9958 L0.5061,0.9224 L0.5913,0.9224 Z M0.5938,0.9182 L0.5037,0.9182 Q0.5012,0.9182,0.5012,0.9203 L0.5012,0.9979 Q0.5012,1,0.5037,1 L0.5938,1 Q0.5962,1,0.5962,0.9979 L0.5962,0.9203 Q0.5962,0.9182,0.5938,0.9182 Z M0.8626,0.9203 L0.7725,0.9203 L0.7725,0.9979 L0.8626,0.9979 L0.8626,0.9203 Z M0.8626,0.9203 L0.7725,0.9203 L0.7725,0.9979 L0.8626,0.9979 L0.8626,0.9203 Z M0.8626,0.9203 L0.7725,0.9203 L0.7725,0.9979 L0.8626,0.9979 L0.8626,0.9203 Z M1,0.9203 L0.9099,0.9203 L0.9099,0.9979 L1,0.9979 L1,0.9203 Z M1,0.9203 L0.9099,0.9203 L0.9099,0.9979 L1,0.9979 L1,0.9203 Z M1,0.9203 L0.9099,0.9203 L0.9099,0.9979 L1,0.9979 L1,0.9203 Z M0.0901,0.1158 L0.0901,0.1888 L0.0049,0.1888 L0.0049,0.1158 L0.0901,0.1158 Z M0.0925,0.1116 L0.0024,0.1116 Q0,0.1116,0,0.1137 L0,0.1909 Q0,0.193,0.0024,0.193 L0.0925,0.193 Q0.095,0.193,0.095,0.1909 L0.095,0.1137 Q0.095,0.1116,0.0925,0.1116 Z M0.2148,0.6086 L0.2148,0.682 L0.1296,0.682 L0.1296,0.6086 L0.2148,0.6086 Z M0.2172,0.6044 L0.1271,0.6044 Q0.1247,0.6044,0.1247,0.6065 L0.1247,0.6841 Q0.1247,0.6862,0.1271,0.6862 L0.2172,0.6862 Q0.2197,0.6862,0.2197,0.6841 L0.2197,0.6065 Q0.2197,0.6044,0.2172,0.6044 Z M0.34,0.1137 L0.2499,0.1137 L0.2499,0.1909 L0.34,0.1909 L0.34,0.1137 Z M0.3376,0.4102 L0.3376,0.4836 L0.2523,0.4836 L0.2523,0.4102 L0.3376,0.4102 Z M0.34,0.406 L0.2499,0.406 Q0.2474,0.406,0.2474,0.4081 L0.2474,0.4857 Q0.2474,0.4878,0.2499,0.4878 L0.34,0.4878 Q0.3424,0.4878,0.3424,0.4857 L0.3424,0.4081 Q0.3424,0.406,0.34,0.406 Z M0.3376,0.7131 L0.3376,0.7865 L0.2523,0.7865 L0.2523,0.7131 L0.3376,0.7131 Z M0.34,0.7089 L0.2499,0.7089 Q0.2474,0.7089,0.2474,0.711 L0.2474,0.7886 Q0.2474,0.7907,0.2499,0.7907 L0.34,0.7907 Q0.3424,0.7907,0.3424,0.7886 L0.3424,0.711 Q0.3424,0.7089,0.34,0.7089 Z M0.4593,0.2227 L0.4593,0.2836 L0.3887,0.2836 L0.3887,0.2227 L0.4593,0.2227 Z M0.4691,0.206 L0.379,0.206 Q0.3746,0.206,0.3719,0.2087 T0.3692,0.2143 L0.3692,0.2919 Q0.3692,0.2957,0.3724,0.298 T0.379,0.3003 L0.4691,0.3003 Q0.4735,0.3003,0.4761,0.2976 T0.4788,0.2919 L0.4788,0.2143 Q0.4788,0.211,0.4756,0.2085 T0.4691,0.206 Z M0.4593,0.3184 L0.4593,0.3792 L0.3887,0.3792 L0.3887,0.3184 L0.4593,0.3184 Z M0.4691,0.3016 L0.379,0.3016 Q0.3746,0.3016,0.3719,0.3043 T0.3692,0.31 L0.3692,0.3876 Q0.3692,0.3914,0.3724,0.3937 T0.379,0.396 L0.4691,0.396 Q0.4735,0.396,0.4761,0.3932 T0.4788,0.3876 L0.4788,0.31 Q0.4788,0.3062,0.4756,0.3039 T0.4691,0.3016 Z M0.4691,0.4081 L0.379,0.4081 L0.379,0.4857 L0.4691,0.4857 L0.4691,0.4081 Z M0.4691,0.5059 L0.379,0.5059 L0.379,0.5835 L0.4691,0.5835 L0.4691,0.5059 Z M0.4593,0.6149 L0.4593,0.6758 L0.3887,0.6758 L0.3887,0.6149 L0.4593,0.6149 Z M0.4691,0.5982 L0.379,0.5982 Q0.3746,0.5982,0.3719,0.6009 T0.3692,0.6065 L0.3692,0.6841 Q0.3692,0.6879,0.3724,0.6902 T0.379,0.6925 L0.4691,0.6925 Q0.4735,0.6925,0.4761,0.6898 T0.4788,0.6841 L0.4788,0.6065 Q0.4788,0.6028,0.4756,0.6005 T0.4691,0.5982 Z M0.5938,0.1137 L0.5037,0.1137 L0.5037,0.1909 L0.5938,0.1909 L0.5938,0.1137 Z M0.5938,0.2143 L0.5037,0.2143 L0.5037,0.2919 L0.5938,0.2919 L0.5938,0.2143 Z M0.5816,0.4186 L0.5816,0.4753 L0.5158,0.4753 L0.5158,0.4186 L0.5816,0.4186 Z M0.5938,0.3977 L0.5037,0.3977 Q0.4983,0.3977,0.4949,0.401 T0.4915,0.4081 L0.4915,0.4857 Q0.4915,0.4904,0.4954,0.4933 T0.5037,0.4962 L0.5938,0.4962 Q0.5991,0.4962,0.6025,0.4929 T0.6059,0.4857 L0.6059,0.4081 Q0.6059,0.4035,0.602,0.4006 T0.5938,0.3977 Z M0.5938,0.5059 L0.5037,0.5059 L0.5037,0.5835 L0.5938,0.5835 L0.5938,0.5059 Z M0.5913,0.7131 L0.5913,0.7865 L0.5061,0.7865 L0.5061,0.7131 L0.5913,0.7131 Z M0.5938,0.7089 L0.5037,0.7089 Q0.5012,0.7089,0.5012,0.711 L0.5012,0.7886 Q0.5012,0.7907,0.5037,0.7907 L0.5938,0.7907 Q0.5962,0.7907,0.5962,0.7886 L0.5962,0.711 Q0.5962,0.7089,0.5938,0.7089 Z M0.7311,0.1137 L0.641,0.1137 L0.641,0.1909 L0.7311,0.1909 L0.7311,0.1137 Z M0.7311,0.2143 L0.641,0.2143 L0.641,0.2919 L0.7311,0.2919 L0.7311,0.2143 Z M0.7311,0.8154 L0.641,0.8154 L0.641,0.8926 L0.7311,0.8926 L0.7311,0.8154 Z M0.7311,0.31 L0.641,0.31 L0.641,0.3876 L0.7311,0.3876 L0.7311,0.31 Z M0.7311,0.8154 L0.641,0.8154 L0.641,0.8926 L0.7311,0.8926 L0.7311,0.8154 Z M0.7311,0.4081 L0.641,0.4081 L0.641,0.4857 L0.7311,0.4857 L0.7311,0.4081 Z M0.7311,0.5059 L0.641,0.5059 L0.641,0.5835 L0.7311,0.5835 L0.7311,0.5059 Z M0.7311,0.711 L0.641,0.711 L0.641,0.7886 L0.7311,0.7886 L0.7311,0.711 Z M0.7311,0.8154 L0.641,0.8154 L0.641,0.8926 L0.7311,0.8926 L0.7311,0.8154 Z M0.8626,0.1137 L0.7725,0.1137 L0.7725,0.1909 L0.8626,0.1909 L0.8626,0.1137 Z M0.8626,0.2143 L0.7725,0.2143 L0.7725,0.2919 L0.8626,0.2919 L0.8626,0.2143 Z M0.8626,0.8154 L0.7725,0.8154 L0.7725,0.8926 L0.8626,0.8926 L0.8626,0.8154 Z M0.8626,0.31 L0.7725,0.31 L0.7725,0.3876 L0.8626,0.3876 L0.8626,0.31 Z M0.8626,0.8154 L0.7725,0.8154 L0.7725,0.8926 L0.8626,0.8926 L0.8626,0.8154 Z M0.8626,0.4081 L0.7725,0.4081 L0.7725,0.4857 L0.8626,0.4857 L0.8626,0.4081 Z M0.8626,0.5059 L0.7725,0.5059 L0.7725,0.5835 L0.8626,0.5835 L0.8626,0.5059 Z M0.8626,0.6065 L0.7725,0.6065 L0.7725,0.6841 L0.8626,0.6841 L0.8626,0.6065 Z M0.8626,0.711 L0.7725,0.711 L0.7725,0.7886 L0.8626,0.7886 L0.8626,0.711 Z M0.8626,0.8154 L0.7725,0.8154 L0.7725,0.8926 L0.8626,0.8926 L0.8626,0.8154 Z M1,0.1137 L0.9099,0.1137 L0.9099,0.1909 L1,0.1909 L1,0.1137 Z M1,0.2143 L0.9099,0.2143 L0.9099,0.2919 L1,0.2919 L1,0.2143 Z M1,0.8154 L0.9099,0.8154 L0.9099,0.8926 L1,0.8926 L1,0.8154 Z M1,0.31 L0.9099,0.31 L0.9099,0.3876 L1,0.3876 L1,0.31 Z M1,0.8154 L0.9099,0.8154 L0.9099,0.8926 L1,0.8926 L1,0.8154 Z M1,0.4081 L0.9099,0.4081 L0.9099,0.4857 L1,0.4857 L1,0.4081 Z M1,0.5059 L0.9099,0.5059 L0.9099,0.5835 L1,0.5835 L1,0.5059 Z M1,0.6065 L0.9099,0.6065 L0.9099,0.6841 L1,0.6841 L1,0.6065 Z M1,0.711 L0.9099,0.711 L0.9099,0.7886 L1,0.7886 L1,0.711 Z M1,0.8154 L0.9099,0.8154 L0.9099,0.8926 L1,0.8926 L1,0.8154 Z",type:0}},"\uE0C6":{type:5,data:{d:"M0.6529,0.018 L0.6529,0.112 L0.7724,0.112 L0.7724,0.018 L0.6529,0.018 Z M0.6411,0 L0.7837,0 Q0.7873,0,0.7902,0.0015 T0.7943,0.005 T0.7956,0.0092 L0.7956,0.1208 Q0.7956,0.125,0.7917,0.1275 T0.7837,0.13 L0.6411,0.13 Q0.6359,0.13,0.6326,0.1271 T0.6292,0.1208 L0.6292,0.0092 Q0.6292,0.005,0.6331,0.0025 T0.6411,0 Z M0.6529,0.018 L0.6529,0.112 L0.7724,0.112 L0.7724,0.018 L0.6529,0.018 Z M0.6411,0 L0.7837,0 Q0.7873,0,0.7902,0.0015 T0.7943,0.005 T0.7956,0.0092 L0.7956,0.1208 Q0.7956,0.125,0.7917,0.1275 T0.7837,0.13 L0.6411,0.13 Q0.6359,0.13,0.6326,0.1271 T0.6292,0.1208 L0.6292,0.0092 Q0.6292,0.005,0.6331,0.0025 T0.6411,0 Z M0.6529,0.018 L0.6529,0.112 L0.7724,0.112 L0.7724,0.018 L0.6529,0.018 Z M0.6411,0 L0.7837,0 Q0.7873,0,0.7902,0.0015 T0.7943,0.005 T0.7956,0.0092 L0.7956,0.1208 Q0.7956,0.125,0.7917,0.1275 T0.7837,0.13 L0.6411,0.13 Q0.6359,0.13,0.6326,0.1271 T0.6292,0.1208 L0.6292,0.0092 Q0.6292,0.005,0.6331,0.0025 T0.6411,0 Z M0.4325,0.0143 L0.4325,0.1158 L0.5628,0.1158 L0.5628,0.0143 L0.4325,0.0143 Z M0.4264,0.0042 L0.5695,0.0042 Q0.5721,0.0042,0.5739,0.0057 T0.5757,0.0092 L0.5757,0.1208 Q0.5757,0.1221,0.5752,0.1231 T0.5736,0.1248 T0.5716,0.1256 T0.5695,0.1258 L0.4264,0.1258 Q0.4238,0.1258,0.422,0.1244 T0.4202,0.1208 L0.4202,0.0092 Q0.4202,0.008,0.4207,0.0069 T0.4222,0.0052 T0.4243,0.0044 T0.4264,0.0042 Z M0.4325,0.0143 L0.4325,0.1158 L0.5628,0.1158 L0.5628,0.0143 L0.4325,0.0143 Z M0.4264,0.0042 L0.5695,0.0042 Q0.5721,0.0042,0.5739,0.0057 T0.5757,0.0092 L0.5757,0.1208 Q0.5757,0.1221,0.5752,0.1231 T0.5736,0.1248 T0.5716,0.1256 T0.5695,0.1258 L0.4264,0.1258 Q0.4238,0.1258,0.422,0.1244 T0.4202,0.1208 L0.4202,0.0092 Q0.4202,0.008,0.4207,0.0069 T0.4222,0.0052 T0.4243,0.0044 T0.4264,0.0042 Z M0.4325,0.0143 L0.4325,0.1158 L0.5628,0.1158 L0.5628,0.0143 L0.4325,0.0143 Z M0.4264,0.0042 L0.5695,0.0042 Q0.5721,0.0042,0.5739,0.0057 T0.5757,0.0092 L0.5757,0.1208 Q0.5757,0.1221,0.5752,0.1231 T0.5736,0.1248 T0.5716,0.1256 T0.5695,0.1258 L0.4264,0.1258 Q0.4238,0.1258,0.422,0.1244 T0.4202,0.1208 L0.4202,0.0092 Q0.4202,0.008,0.4207,0.0069 T0.4222,0.0052 T0.4243,0.0044 T0.4264,0.0042 Z M0.2178,0.0092 L0.3605,0.0092 L0.3605,0.1208 L0.2178,0.1208 L0.2178,0.0092 Z M0.2178,0.0092 L0.3605,0.0092 L0.3605,0.1208 L0.2178,0.1208 L0.2178,0.0092 Z M0.2178,0.0092 L0.3605,0.0092 L0.3605,0.1208 L0.2178,0.1208 L0.2178,0.0092 Z M0,0.0092 L0.1432,0.0092 L0.1432,0.1208 L0,0.1208 L0,0.0092 Z M0,0.0092 L0.1432,0.0092 L0.1432,0.1208 L0,0.1208 L0,0.0092 Z M0,0.0092 L0.1432,0.0092 L0.1432,0.1208 L0,0.1208 L0,0.0092 Z M0.8574,0.3217 L0.8574,0.4098 L0.9691,0.4098 L0.9691,0.3217 L0.8574,0.3217 Z M0.8419,0.2978 L0.9846,0.2978 Q0.9892,0.2978,0.9928,0.2997 T0.9982,0.3043 T1,0.31 L1,0.4216 Q1,0.427,0.9951,0.4304 T0.9846,0.4337 L0.8419,0.4337 Q0.8352,0.4337,0.8308,0.4299 T0.8265,0.4216 L0.8265,0.31 Q0.8265,0.3062,0.829,0.3035 T0.835,0.2993 T0.8419,0.2978 Z M0.8574,0.888 L0.8574,0.9757 L0.9691,0.9757 L0.9691,0.888 L0.8574,0.888 Z M0.8419,0.8637 L0.9846,0.8637 Q0.9892,0.8637,0.9928,0.8658 T0.9982,0.8706 T1,0.8758 L1,0.9878 Q1,0.9929,0.9951,0.9964 T0.9846,1 L0.8419,1 Q0.8352,1,0.8308,0.996 T0.8265,0.9878 L0.8265,0.8758 Q0.8265,0.8708,0.8314,0.8672 T0.8419,0.8637 Z M0.6509,0.169 L0.6509,0.2706 L0.7806,0.2706 L0.7806,0.169 L0.6509,0.169 Z M0.6442,0.159 L0.7868,0.159 Q0.7899,0.159,0.7917,0.1604 T0.7935,0.164 L0.7935,0.2756 Q0.7935,0.2781,0.7915,0.2796 T0.7868,0.281 L0.6442,0.281 Q0.6416,0.281,0.6395,0.2794 T0.6375,0.2756 L0.6375,0.164 Q0.6375,0.1619,0.6398,0.1604 T0.6442,0.159 Z M0.6632,0.6044 L0.6632,0.6858 L0.7678,0.6858 L0.7678,0.6044 L0.6632,0.6044 Z M0.6442,0.5742 L0.7868,0.5742 Q0.7951,0.5742,0.8007,0.5791 T0.8064,0.5893 L0.8064,0.7013 Q0.8064,0.7076,0.8002,0.712 T0.7868,0.7164 L0.6442,0.7164 Q0.6359,0.7164,0.6305,0.7114 T0.6251,0.7013 L0.6251,0.5893 Q0.6251,0.5847,0.6282,0.5812 T0.6357,0.5759 T0.6442,0.5742 Z M0.4264,0.164 L0.5695,0.164 L0.5695,0.2756 L0.4264,0.2756 L0.4264,0.164 Z M0.4325,0.315 L0.4325,0.4165 L0.5628,0.4165 L0.5628,0.315 L0.4325,0.315 Z M0.4264,0.3049 L0.5695,0.3049 Q0.5721,0.3049,0.5739,0.3064 T0.5757,0.31 L0.5757,0.4216 Q0.5757,0.4237,0.5736,0.4251 T0.5695,0.4266 L0.4264,0.4266 Q0.4238,0.4266,0.422,0.4251 T0.4202,0.4216 L0.4202,0.31 Q0.4202,0.3087,0.4207,0.3077 T0.4222,0.306 T0.4243,0.3052 T0.4264,0.3049 Z M0.4264,0.4476 L0.5695,0.4476 L0.5695,0.5596 L0.4264,0.5596 L0.4264,0.4476 Z M0.4392,0.7408 L0.4392,0.8326 L0.5561,0.8326 L0.5561,0.7408 L0.4392,0.7408 Z M0.4264,0.7206 L0.5695,0.7206 Q0.5747,0.7206,0.5783,0.724 T0.5819,0.7307 L0.5819,0.8427 Q0.5819,0.8469,0.5778,0.8498 T0.5695,0.8528 L0.4264,0.8528 Q0.4207,0.8528,0.4171,0.8496 T0.4135,0.8427 L0.4135,0.7307 Q0.4135,0.7265,0.4176,0.7236 T0.4264,0.7206 Z M0.2178,0.164 L0.3605,0.164 L0.3605,0.2756 L0.2178,0.2756 L0.2178,0.164 Z M0.2178,0.31 L0.3605,0.31 L0.3605,0.4216 L0.2178,0.4216 L0.2178,0.31 Z M0.2178,0.5893 L0.3605,0.5893 L0.3605,0.7013 L0.2178,0.7013 L0.2178,0.5893 Z M0.2178,0.7307 L0.3605,0.7307 L0.3605,0.8427 L0.2178,0.8427 L0.2178,0.7307 Z M0.2178,0.8758 L0.3605,0.8758 L0.3605,0.9878 L0.2178,0.9878 L0.2178,0.8758 Z M0,0.164 L0.1432,0.164 L0.1432,0.2756 L0,0.2756 L0,0.164 Z M0,0.31 L0.1432,0.31 L0.1432,0.4216 L0,0.4216 L0,0.31 Z M0,0.4476 L0.1432,0.4476 L0.1432,0.5596 L0,0.5596 L0,0.4476 Z M0,0.5893 L0.1432,0.5893 L0.1432,0.7013 L0,0.7013 L0,0.5893 Z M0,0.7307 L0.1432,0.7307 L0.1432,0.8427 L0,0.8427 L0,0.7307 Z M0,0.8758 L0.1432,0.8758 L0.1432,0.9878 L0,0.9878 L0,0.8758 Z",type:0}},"\uE0C7":{type:5,data:{d:"M0.3476,0.018 L0.3476,0.112 L0.2276,0.112 L0.2276,0.018 L0.3476,0.018 Z M0.3594,0 L0.2163,0 Q0.2132,0,0.2104,0.0015 T0.2062,0.005 T0.2049,0.0092 L0.2049,0.1208 Q0.2049,0.1237,0.2067,0.1258 T0.2111,0.129 T0.2163,0.13 L0.3594,0.13 Q0.3641,0.13,0.3674,0.1271 T0.3708,0.1208 L0.3708,0.0092 Q0.3708,0.005,0.3669,0.0025 T0.3594,0 Z M0.3476,0.018 L0.3476,0.112 L0.2276,0.112 L0.2276,0.018 L0.3476,0.018 Z M0.3594,0 L0.2163,0 Q0.2132,0,0.2104,0.0015 T0.2062,0.005 T0.2049,0.0092 L0.2049,0.1208 Q0.2049,0.1237,0.2067,0.1258 T0.2111,0.129 T0.2163,0.13 L0.3594,0.13 Q0.3641,0.13,0.3674,0.1271 T0.3708,0.1208 L0.3708,0.0092 Q0.3708,0.005,0.3669,0.0025 T0.3594,0 Z M0.3476,0.018 L0.3476,0.112 L0.2276,0.112 L0.2276,0.018 L0.3476,0.018 Z M0.3594,0 L0.2163,0 Q0.2132,0,0.2104,0.0015 T0.2062,0.005 T0.2049,0.0092 L0.2049,0.1208 Q0.2049,0.1237,0.2067,0.1258 T0.2111,0.129 T0.2163,0.13 L0.3594,0.13 Q0.3641,0.13,0.3674,0.1271 T0.3708,0.1208 L0.3708,0.0092 Q0.3708,0.005,0.3669,0.0025 T0.3594,0 Z M0.5675,0.0143 L0.5675,0.1158 L0.4377,0.1158 L0.4377,0.0143 L0.5675,0.0143 Z M0.5736,0.0042 L0.431,0.0042 Q0.4284,0.0042,0.4264,0.0057 T0.4243,0.0092 L0.4243,0.1208 Q0.4243,0.1221,0.4251,0.1231 T0.4269,0.1248 T0.4289,0.1256 T0.431,0.1258 L0.5736,0.1258 Q0.5767,0.1258,0.5785,0.1244 T0.5803,0.1208 L0.5803,0.0092 Q0.5803,0.008,0.5798,0.0069 T0.5783,0.0052 T0.5762,0.0044 T0.5736,0.0042 Z M0.5675,0.0143 L0.5675,0.1158 L0.4377,0.1158 L0.4377,0.0143 L0.5675,0.0143 Z M0.5736,0.0042 L0.431,0.0042 Q0.4284,0.0042,0.4264,0.0057 T0.4243,0.0092 L0.4243,0.1208 Q0.4243,0.1221,0.4251,0.1231 T0.4269,0.1248 T0.4289,0.1256 T0.431,0.1258 L0.5736,0.1258 Q0.5767,0.1258,0.5785,0.1244 T0.5803,0.1208 L0.5803,0.0092 Q0.5803,0.008,0.5798,0.0069 T0.5783,0.0052 T0.5762,0.0044 T0.5736,0.0042 Z M0.5675,0.0143 L0.5675,0.1158 L0.4377,0.1158 L0.4377,0.0143 L0.5675,0.0143 Z M0.5736,0.0042 L0.431,0.0042 Q0.4284,0.0042,0.4264,0.0057 T0.4243,0.0092 L0.4243,0.1208 Q0.4243,0.1221,0.4251,0.1231 T0.4269,0.1248 T0.4289,0.1256 T0.431,0.1258 L0.5736,0.1258 Q0.5767,0.1258,0.5785,0.1244 T0.5803,0.1208 L0.5803,0.0092 Q0.5803,0.008,0.5798,0.0069 T0.5783,0.0052 T0.5762,0.0044 T0.5736,0.0042 Z M0.7827,0.0092 L0.6395,0.0092 L0.6395,0.1208 L0.7827,0.1208 L0.7827,0.0092 Z M0.7827,0.0092 L0.6395,0.0092 L0.6395,0.1208 L0.7827,0.1208 L0.7827,0.0092 Z M0.7827,0.0092 L0.6395,0.0092 L0.6395,0.1208 L0.7827,0.1208 L0.7827,0.0092 Z M1,0.0092 L0.8574,0.0092 L0.8574,0.1208 L1,0.1208 L1,0.0092 Z M1,0.0092 L0.8574,0.0092 L0.8574,0.1208 L1,0.1208 L1,0.0092 Z M1,0.0092 L0.8574,0.0092 L0.8574,0.1208 L1,0.1208 L1,0.0092 Z M0.1432,0.3217 L0.1432,0.4098 L0.0309,0.4098 L0.0309,0.3217 L0.1432,0.3217 Z M0.1586,0.2978 L0.0154,0.2978 Q0.0088,0.2978,0.0044,0.3016 T0,0.31 L0,0.4216 Q0,0.427,0.0049,0.4304 T0.0154,0.4337 L0.1586,0.4337 Q0.1648,0.4337,0.1694,0.4299 T0.174,0.4216 L0.174,0.31 Q0.174,0.3062,0.1715,0.3035 T0.1653,0.2993 T0.1586,0.2978 Z M0.1432,0.888 L0.1432,0.9757 L0.0309,0.9757 L0.0309,0.888 L0.1432,0.888 Z M0.1586,0.8637 L0.0154,0.8637 Q0.0108,0.8637,0.0072,0.8658 T0.0018,0.8706 T0,0.8758 L0,0.9878 Q0,0.9929,0.0049,0.9964 T0.0154,1 L0.1586,1 Q0.1648,1,0.1694,0.996 T0.174,0.9878 L0.174,0.8758 Q0.174,0.8725,0.1715,0.8695 T0.1653,0.8651 T0.1586,0.8637 Z M0.3496,0.169 L0.3496,0.2706 L0.2194,0.2706 L0.2194,0.169 L0.3496,0.169 Z M0.3563,0.159 L0.2132,0.159 Q0.2106,0.159,0.2088,0.1604 T0.207,0.164 L0.207,0.2756 Q0.207,0.2781,0.2091,0.2796 T0.2132,0.281 L0.3563,0.281 Q0.3589,0.281,0.3607,0.2794 T0.3625,0.2756 L0.3625,0.164 Q0.3625,0.1619,0.3605,0.1604 T0.3563,0.159 Z M0.3368,0.6044 L0.3368,0.6858 L0.2327,0.6858 L0.2327,0.6044 L0.3368,0.6044 Z M0.3563,0.5742 L0.2132,0.5742 Q0.2049,0.5742,0.1993,0.5791 T0.1936,0.5893 L0.1936,0.7013 Q0.1936,0.7076,0.2001,0.712 T0.2132,0.7164 L0.3563,0.7164 Q0.3641,0.7164,0.3697,0.7114 T0.3754,0.7013 L0.3754,0.5893 Q0.3754,0.5847,0.3723,0.5812 T0.3648,0.5759 T0.3563,0.5742 Z M0.5736,0.164 L0.431,0.164 L0.431,0.2756 L0.5736,0.2756 L0.5736,0.164 Z M0.5675,0.315 L0.5675,0.4165 L0.4377,0.4165 L0.4377,0.315 L0.5675,0.315 Z M0.5736,0.3049 L0.431,0.3049 Q0.4284,0.3049,0.4264,0.3064 T0.4243,0.31 L0.4243,0.4216 Q0.4243,0.4237,0.4266,0.4251 T0.431,0.4266 L0.5736,0.4266 Q0.5767,0.4266,0.5785,0.4251 T0.5803,0.4216 L0.5803,0.31 Q0.5803,0.3087,0.5798,0.3077 T0.5783,0.306 T0.5762,0.3052 T0.5736,0.3049 Z M0.5736,0.4476 L0.431,0.4476 L0.431,0.5596 L0.5736,0.5596 L0.5736,0.4476 Z M0.5613,0.7408 L0.5613,0.8326 L0.4439,0.8326 L0.4439,0.7408 L0.5613,0.7408 Z M0.5736,0.7206 L0.431,0.7206 Q0.4253,0.7206,0.4217,0.724 T0.4181,0.7307 L0.4181,0.8427 Q0.4181,0.8469,0.4222,0.8498 T0.431,0.8528 L0.5736,0.8528 Q0.5778,0.8528,0.5808,0.8511 T0.5855,0.8471 T0.587,0.8427 L0.587,0.7307 Q0.587,0.7265,0.5826,0.7236 T0.5736,0.7206 Z M0.7827,0.164 L0.6395,0.164 L0.6395,0.2756 L0.7827,0.2756 L0.7827,0.164 Z M0.7827,0.31 L0.6395,0.31 L0.6395,0.4216 L0.7827,0.4216 L0.7827,0.31 Z M0.7827,0.5893 L0.6395,0.5893 L0.6395,0.7013 L0.7827,0.7013 L0.7827,0.5893 Z M0.7827,0.7307 L0.6395,0.7307 L0.6395,0.8427 L0.7827,0.8427 L0.7827,0.7307 Z M0.7827,0.8758 L0.6395,0.8758 L0.6395,0.9878 L0.7827,0.9878 L0.7827,0.8758 Z M1,0.164 L0.8574,0.164 L0.8574,0.2756 L1,0.2756 L1,0.164 Z M1,0.31 L0.8574,0.31 L0.8574,0.4216 L1,0.4216 L1,0.31 Z M1,0.4476 L0.8574,0.4476 L0.8574,0.5596 L1,0.5596 L1,0.4476 Z M1,0.5893 L0.8574,0.5893 L0.8574,0.7013 L1,0.7013 L1,0.5893 Z M1,0.7307 L0.8574,0.7307 L0.8574,0.8427 L1,0.8427 L1,0.7307 Z M1,0.8758 L0.8574,0.8758 L0.8574,0.9878 L1,0.9878 L1,0.8758 Z",type:0}},"\uE0C8":{type:5,data:{d:"M0.0008,0.9979 Q0.0008,1,0.0032,1 Q0.0482,1,0.0602,0.9975 Q0.0667,0.9963,0.0847,0.9917 T0.1084,0.9859 Q0.1124,0.9851,0.1221,0.9851 L0.1253,0.9851 L0.1285,0.9851 Q0.1518,0.9851,0.1655,0.9809 Q0.1695,0.9801,0.1731,0.9788 T0.1791,0.9766 T0.1839,0.9747 T0.1888,0.9732 L0.1936,0.972 T0.1988,0.9712 T0.2048,0.971 L0.2096,0.971 Q0.2201,0.9714,0.2233,0.9714 T0.2345,0.9693 Q0.2386,0.9685,0.2502,0.9674 T0.2715,0.966 L0.2811,0.9656 Q0.2916,0.9647,0.2916,0.9573 Q0.2916,0.954,0.2892,0.9515 T0.2819,0.9486 Q0.2755,0.9482,0.2683,0.9482 Q0.2643,0.9482,0.2582,0.9484 T0.2498,0.9486 Q0.2426,0.9486,0.2402,0.9473 Q0.2386,0.9469,0.2317,0.943 T0.2161,0.937 Q0.2104,0.9357,0.1992,0.933 T0.1831,0.9291 Q0.1807,0.9287,0.1783,0.9285 T0.1739,0.928 T0.1703,0.9276 T0.1675,0.9272 T0.1655,0.9266 T0.1639,0.9253 Q0.1598,0.9216,0.1462,0.9216 L0.143,0.9216 L0.1398,0.9216 L0.1365,0.9216 Q0.1197,0.9195,0.1197,0.9154 L0.1197,0.9154 Q0.1205,0.9121,0.1373,0.9088 T0.1703,0.9054 Q0.1791,0.9054,0.1863,0.904 T0.1984,0.9011 T0.2064,0.8992 Q0.2402,0.8967,0.2506,0.8934 Q0.2538,0.8926,0.2602,0.8899 T0.2707,0.8872 Q0.2715,0.8872,0.2731,0.8876 Q0.2795,0.8884,0.2884,0.8884 Q0.3068,0.8884,0.3092,0.8826 L0.3092,0.8797 Q0.3092,0.8772,0.3076,0.8747 T0.3044,0.8706 T0.3028,0.8681 Q0.3076,0.8656,0.3237,0.8656 Q0.3317,0.8656,0.3622,0.8623 Q0.3655,0.8623,0.3867,0.8617 T0.4217,0.8602 Q0.4241,0.8598,0.4289,0.8598 L0.4345,0.8598 L0.441,0.8598 Q0.4578,0.8598,0.4667,0.8586 Q0.4739,0.8573,0.4851,0.8567 T0.5004,0.8552 Q0.5012,0.8552,0.5108,0.855 T0.5269,0.853 T0.5333,0.8461 Q0.5333,0.8445,0.5325,0.8432 T0.5309,0.8409 T0.5289,0.8391 T0.5261,0.8378 L0.5229,0.837 T0.5185,0.8362 T0.5133,0.8355 T0.5076,0.8349 T0.502,0.8341 Q0.4932,0.8324,0.4859,0.8324 Q0.4827,0.8324,0.4787,0.8328 T0.4731,0.8333 Q0.4707,0.8333,0.4683,0.8324 Q0.4482,0.825,0.4394,0.825 Q0.4369,0.825,0.4345,0.8254 Q0.4225,0.827,0.4153,0.827 Q0.4088,0.827,0.4064,0.8258 Q0.3976,0.8204,0.3751,0.8204 Q0.3703,0.8204,0.3667,0.8214 T0.3622,0.8225 Q0.3598,0.8225,0.3558,0.82 Q0.351,0.8175,0.3402,0.8167 T0.3177,0.8156 T0.3028,0.8146 L0.2956,0.8121 T0.2871,0.8094 T0.2771,0.8073 T0.2635,0.8063 Q0.261,0.8063,0.2586,0.8067 Q0.2378,0.8071,0.2273,0.8071 Q0.2072,0.8071,0.2024,0.8051 Q0.1976,0.8034,0.1932,0.8026 T0.1867,0.8013 T0.1847,0.8001 L0.1847,0.7993 Q0.1855,0.7984,0.1855,0.7978 T0.1859,0.7966 T0.1867,0.7959 T0.188,0.7955 T0.1896,0.7951 T0.1916,0.7949 T0.1944,0.7945 T0.1984,0.7941 T0.2032,0.7939 Q0.212,0.7926,0.2325,0.7918 T0.2562,0.7905 Q0.2691,0.7893,0.2787,0.7847 Q0.2835,0.7827,0.2968,0.7791 T0.3149,0.7756 Q0.3189,0.7756,0.3305,0.7733 T0.3446,0.771 L0.3454,0.771 Q0.3462,0.771,0.3498,0.7721 T0.3574,0.774 T0.3655,0.7748 Q0.3703,0.7748,0.3743,0.7731 T0.3823,0.7708 T0.3916,0.77 T0.3992,0.7694 Q0.4008,0.7694,0.4076,0.7688 T0.4205,0.7675 L0.4305,0.7665 Q0.4345,0.7657,0.4402,0.7617 T0.4458,0.7545 Q0.4458,0.7503,0.4353,0.7487 Q0.4297,0.7478,0.4209,0.7462 T0.4044,0.7433 T0.3904,0.7416 L0.3847,0.7416 Q0.3807,0.7416,0.3747,0.7422 T0.3663,0.7428 T0.3606,0.7424 Q0.3582,0.742,0.3562,0.7418 T0.3522,0.7412 T0.3482,0.7406 T0.3446,0.7401 T0.341,0.7397 T0.3373,0.7393 T0.3341,0.7391 L0.3293,0.7391 Q0.3277,0.7395,0.3253,0.7395 Q0.3205,0.7395,0.3052,0.7387 T0.2835,0.7379 Q0.2755,0.7379,0.253,0.7325 Q0.2506,0.7316,0.2462,0.731 T0.2382,0.7296 T0.2305,0.7271 T0.2181,0.7234 T0.2048,0.7196 T0.2,0.7155 Q0.2,0.7142,0.2016,0.713 Q0.208,0.7059,0.2285,0.6978 T0.2618,0.6898 Q0.2739,0.6898,0.2831,0.6848 T0.2956,0.6794 Q0.3028,0.6786,0.3289,0.6765 T0.3566,0.674 Q0.3582,0.674,0.3855,0.6723 T0.4406,0.6688 T0.4755,0.6653 Q0.5004,0.6607,0.5124,0.6599 L0.5165,0.6599 Q0.5213,0.6599,0.5277,0.6605 T0.5373,0.6611 Q0.543,0.6611,0.5494,0.6599 Q0.592,0.6524,0.6,0.6524 Q0.6064,0.6524,0.61,0.6499 T0.6161,0.6474 Q0.6177,0.6474,0.6261,0.6495 T0.6418,0.6516 L0.6482,0.6516 Q0.653,0.6512,0.6651,0.6506 T0.6876,0.6493 T0.7084,0.6477 T0.7229,0.645 Q0.7269,0.6437,0.7333,0.6437 Q0.7373,0.6437,0.7458,0.6443 T0.7574,0.645 Q0.7614,0.645,0.7631,0.6445 T0.7655,0.6441 Q0.7671,0.6441,0.7723,0.6448 T0.7823,0.6454 Q0.788,0.6454,0.7952,0.6445 Q0.8233,0.6408,0.8723,0.6367 Q0.9012,0.6342,0.9092,0.6342 L0.9165,0.6342 L0.9205,0.6342 Q0.9277,0.6342,0.9382,0.6323 T0.9526,0.6304 Q0.9534,0.6304,0.9594,0.6307 T0.9695,0.6309 Q0.9976,0.6309,0.9992,0.6234 Q1,0.6201,1,0.618 Q1,0.6089,0.9775,0.608 Q0.9703,0.6076,0.9582,0.6076 Q0.9518,0.6076,0.9394,0.6078 T0.9213,0.608 Q0.9036,0.608,0.8972,0.6072 Q0.894,0.6068,0.8871,0.6058 T0.8751,0.6039 T0.8627,0.6024 T0.8506,0.6018 L0.8474,0.6018 Q0.841,0.6022,0.8281,0.6041 T0.8112,0.606 Q0.8096,0.606,0.808,0.6056 Q0.7783,0.6002,0.7647,0.6002 Q0.7598,0.6002,0.7454,0.6006 T0.7261,0.601 Q0.7221,0.601,0.7145,0.6022 T0.7036,0.6035 Q0.6996,0.6035,0.6964,0.6022 Q0.6723,0.5902,0.6442,0.5902 Q0.6426,0.5902,0.6386,0.5904 T0.6337,0.5906 Q0.6273,0.5906,0.6249,0.5894 L0.6177,0.5856 T0.6116,0.5838 T0.6016,0.5825 T0.5855,0.5823 Q0.5719,0.5823,0.5574,0.5798 T0.5373,0.5774 L0.5341,0.5774 Q0.5293,0.5778,0.5213,0.5786 T0.51,0.5794 Q0.5036,0.5794,0.4988,0.5769 Q0.4932,0.574,0.4771,0.574 Q0.4723,0.574,0.4631,0.5745 T0.4498,0.5749 Q0.4418,0.5749,0.4394,0.5736 Q0.4353,0.5724,0.4305,0.5715 T0.4225,0.5707 T0.4145,0.5705 T0.4056,0.5699 Q0.4008,0.5691,0.398,0.5689 T0.394,0.5689 T0.3908,0.5686 T0.3855,0.5674 Q0.3831,0.567,0.3811,0.5662 T0.3779,0.5645 T0.3743,0.563 T0.3695,0.5624 Q0.3655,0.5624,0.3594,0.5635 T0.3494,0.5645 T0.3406,0.5635 T0.3325,0.5624 Q0.3309,0.5624,0.3301,0.5628 L0.3141,0.5628 Q0.2635,0.5628,0.2506,0.5612 Q0.2474,0.5608,0.2434,0.5608 Q0.2402,0.5608,0.2349,0.561 T0.2273,0.5612 Q0.2209,0.5612,0.2177,0.5595 Q0.2145,0.557,0.2145,0.5558 Q0.2169,0.5537,0.2345,0.5521 Q0.2876,0.5475,0.3028,0.5425 Q0.3068,0.5413,0.3149,0.5396 T0.3309,0.5367 T0.3478,0.5338 T0.3606,0.5309 Q0.3631,0.5305,0.3755,0.5259 T0.3968,0.5214 Q0.3992,0.5214,0.4024,0.5218 T0.4096,0.5222 Q0.4161,0.5222,0.4213,0.5209 T0.4313,0.5185 T0.4402,0.5172 Q0.4418,0.5168,0.447,0.5168 L0.4558,0.5168 T0.4639,0.5162 T0.4707,0.5141 T0.4731,0.5102 Q0.4731,0.5089,0.4723,0.5081 Q0.4699,0.5019,0.4627,0.4994 T0.4369,0.4965 Q0.4273,0.4961,0.4193,0.4946 T0.4048,0.4915 T0.3952,0.4894 Q0.392,0.4886,0.388,0.4886 Q0.3847,0.4886,0.3775,0.4892 T0.3647,0.4898 Q0.3598,0.4898,0.355,0.4894 Q0.3165,0.4861,0.3141,0.4853 Q0.2779,0.4774,0.2715,0.4774 Q0.2699,0.4774,0.2683,0.4776 T0.2627,0.4778 Q0.2498,0.4778,0.2281,0.4762 Q0.2241,0.4749,0.2233,0.4737 Q0.2249,0.472,0.2321,0.4708 Q0.2402,0.4695,0.2554,0.4695 L0.2675,0.4695 L0.2795,0.4695 Q0.294,0.4695,0.2996,0.4679 Q0.3141,0.4629,0.3373,0.4616 Q0.3414,0.4612,0.3466,0.4606 T0.3582,0.4589 T0.3687,0.4562 T0.3727,0.4525 Q0.3727,0.4509,0.3703,0.4492 Q0.3639,0.4455,0.3474,0.4419 T0.3213,0.4384 L0.3157,0.4384 L0.31,0.4384 Q0.294,0.4384,0.2859,0.4363 Q0.2795,0.4347,0.2691,0.4347 L0.2618,0.4347 L0.2546,0.4347 Q0.2458,0.4347,0.2394,0.4338 Q0.2257,0.4318,0.2193,0.4303 T0.2092,0.4266 T0.2052,0.4224 T0.2024,0.4154 T0.196,0.4052 Q0.1912,0.3994,0.1867,0.3949 T0.1807,0.3884 T0.1791,0.3849 Q0.1791,0.3824,0.1839,0.3745 Q0.1871,0.3687,0.1944,0.3637 T0.2072,0.3561 T0.2221,0.3501 T0.2321,0.3463 Q0.2353,0.3455,0.241,0.3445 T0.2522,0.3428 T0.2639,0.3411 T0.2731,0.3384 T0.2956,0.3351 T0.3197,0.3326 Q0.3213,0.3322,0.3237,0.3322 T0.3325,0.3331 T0.3414,0.3339 Q0.3478,0.3339,0.3518,0.3314 Q0.3606,0.3264,0.3703,0.3264 Q0.3775,0.3264,0.3847,0.3293 Q0.3888,0.331,0.396,0.331 Q0.4024,0.331,0.4116,0.3295 T0.4265,0.3266 T0.4414,0.3227 T0.4514,0.3202 Q0.4578,0.3181,0.4839,0.3152 T0.5112,0.3123 T0.5177,0.3119 T0.5285,0.3111 T0.5398,0.3096 T0.549,0.3065 T0.5526,0.3015 Q0.5526,0.2999,0.5518,0.2982 Q0.547,0.2903,0.5386,0.2883 T0.5165,0.2862 Q0.5116,0.2862,0.5056,0.2866 T0.4972,0.287 Q0.4884,0.287,0.4787,0.2833 Q0.4594,0.2758,0.4265,0.2758 Q0.4169,0.2758,0.4129,0.2766 Q0.4112,0.2771,0.4104,0.2771 Q0.4088,0.2771,0.4056,0.2748 T0.3968,0.2721 Q0.3695,0.2696,0.359,0.2659 Q0.355,0.2646,0.351,0.2646 T0.3426,0.2661 T0.3365,0.2675 T0.3333,0.2659 Q0.3277,0.2605,0.3116,0.2553 T0.2859,0.2501 L0.2843,0.2501 L0.2819,0.2501 Q0.2779,0.2501,0.2723,0.2493 T0.2586,0.2472 T0.2474,0.2455 Q0.1799,0.236,0.1719,0.236 Q0.1663,0.236,0.1606,0.235 T0.1502,0.2316 T0.1454,0.2265 Q0.1454,0.2223,0.1558,0.2173 Q0.1679,0.2115,0.1859,0.2092 T0.2185,0.207 T0.2353,0.2057 Q0.2369,0.2049,0.2502,0.2041 T0.2799,0.2022 T0.302,0.2007 Q0.3084,0.1999,0.3245,0.1954 T0.347,0.1908 Q0.3502,0.1908,0.3534,0.1916 Q0.3663,0.197,0.388,0.197 Q0.404,0.197,0.4088,0.1929 Q0.4096,0.192,0.4108,0.192 T0.4177,0.1945 T0.4277,0.197 T0.4369,0.1949 Q0.4442,0.1908,0.4843,0.1875 Q0.4892,0.1871,0.4968,0.1839 T0.5084,0.1808 L0.5108,0.1808 Q0.5213,0.1825,0.5454,0.1825 Q0.5823,0.1825,0.5992,0.1779 Q0.6096,0.1746,0.6217,0.1746 Q0.6249,0.1746,0.6309,0.1748 T0.6394,0.175 Q0.6434,0.175,0.6466,0.1746 Q0.6474,0.1746,0.6594,0.1738 T0.6787,0.1713 T0.6892,0.1659 Q0.6924,0.1634,0.6924,0.1593 Q0.6924,0.1547,0.6888,0.151 T0.6795,0.1472 Q0.6779,0.1472,0.6763,0.1477 Q0.6699,0.1493,0.6667,0.1493 Q0.661,0.1493,0.6506,0.1456 Q0.6329,0.1394,0.6129,0.1394 Q0.6048,0.1394,0.5992,0.1377 T0.5888,0.136 T0.5803,0.1377 T0.5751,0.1394 Q0.5711,0.1394,0.5639,0.1369 Q0.5365,0.1273,0.5116,0.1273 Q0.4876,0.1273,0.4667,0.1253 Q0.4627,0.1248,0.4542,0.1211 T0.4337,0.1174 L0.4305,0.1174 Q0.4217,0.1178,0.4153,0.119 T0.408,0.1203 Q0.4056,0.1203,0.4,0.117 Q0.3976,0.1153,0.396,0.1136 T0.3932,0.1112 T0.39,0.1099 T0.3847,0.1095 Q0.3799,0.1095,0.3687,0.1103 Q0.355,0.1112,0.3434,0.1141 T0.3301,0.117 Q0.3261,0.117,0.3229,0.1145 Q0.3181,0.1116,0.3052,0.1087 T0.2787,0.1043 T0.2546,0.1029 Q0.2506,0.1029,0.2474,0.1033 Q0.2418,0.1037,0.2349,0.1054 T0.2249,0.107 Q0.2225,0.107,0.2193,0.1066 Q0.2024,0.1024,0.1863,0.1024 Q0.1823,0.1024,0.1562,0.0971 T0.1269,0.0917 T0.1161,0.0896 T0.106,0.0854 Q0.1076,0.0846,0.11,0.0842 Q0.1173,0.0821,0.1261,0.0821 Q0.1301,0.0821,0.1369,0.0825 T0.1462,0.083 Q0.1494,0.083,0.151,0.0825 T0.1831,0.0813 T0.2201,0.0784 T0.243,0.074 T0.2667,0.0718 Q0.2707,0.0718,0.2755,0.0724 T0.2843,0.073 T0.2936,0.0724 T0.3024,0.0705 T0.3072,0.068 T0.3092,0.0657 T0.3108,0.0647 Q0.3116,0.0643,0.3133,0.0643 L0.3157,0.0643 L0.3181,0.0643 Q0.3446,0.0643,0.3446,0.0556 T0.3205,0.0469 L0.3189,0.0469 Q0.3157,0.0469,0.3157,0.0465 Q0.3084,0.0427,0.2835,0.0386 Q0.2739,0.0369,0.2675,0.0342 T0.2538,0.0299 Q0.249,0.029,0.245,0.029 T0.2378,0.0303 T0.2321,0.0315 Q0.2305,0.0315,0.2273,0.0307 Q0.2201,0.0286,0.2004,0.0272 T0.1775,0.0245 Q0.1735,0.0228,0.1663,0.0226 T0.1522,0.0197 T0.1345,0.0145 T0.1124,0.0079 Q0.0996,0.0033,0.0671,0.0044 T0.0297,0.0041 Q0.0169,0,0.0024,0.0017 Q0,0.0021,0,0.0037 Z M0.0064,0.9954 L0.0056,0.0058 Q0.0177,0.005,0.0281,0.0083 Q0.0345,0.01,0.0675,0.0089 T0.1108,0.012 Q0.1221,0.0162,0.1329,0.0187 T0.1498,0.0236 T0.1606,0.0268 T0.1691,0.0274 T0.1759,0.0286 Q0.1807,0.0303,0.2,0.0315 T0.2257,0.0348 Q0.2305,0.0361,0.2337,0.0361 Q0.2361,0.0361,0.2398,0.0348 T0.2466,0.0336 Q0.249,0.0336,0.2522,0.034 Q0.2586,0.0353,0.2655,0.0382 T0.2827,0.0427 Q0.3068,0.0469,0.3124,0.0502 Q0.3157,0.0523,0.3237,0.0523 L0.3277,0.0523 L0.3309,0.0523 Q0.3398,0.0523,0.3398,0.0556 Q0.3398,0.0581,0.3341,0.0587 T0.3205,0.0593 T0.3092,0.0603 T0.3036,0.0643 T0.2932,0.068 Q0.2884,0.0684,0.2843,0.0684 Q0.2811,0.0684,0.2763,0.0678 T0.2667,0.0672 Q0.2586,0.0672,0.2422,0.0697 T0.2177,0.0747 Q0.2137,0.0759,0.1831,0.0767 T0.1494,0.0784 L0.1474,0.0784 T0.1398,0.078 T0.1285,0.0776 Q0.1173,0.0776,0.1084,0.08 Q0.1004,0.0817,0.1004,0.0846 Q0.1004,0.0867,0.104,0.0888 T0.1124,0.0923 T0.1213,0.0948 T0.1269,0.0958 T0.155,0.1014 T0.1863,0.107 Q0.2016,0.107,0.2185,0.1107 Q0.2217,0.1116,0.2257,0.1116 Q0.2289,0.1116,0.2365,0.1099 T0.2482,0.1074 L0.2538,0.1074 Q0.2683,0.1074,0.2912,0.1107 T0.3197,0.1182 Q0.3245,0.1215,0.3301,0.1215 Q0.3333,0.1215,0.3454,0.1184 T0.3687,0.1145 Q0.3735,0.1141,0.3779,0.1139 T0.3843,0.1134 T0.3871,0.1132 Q0.3896,0.1132,0.39,0.1136 T0.392,0.1161 T0.3968,0.1203 Q0.404,0.1248,0.408,0.1248 Q0.4096,0.1248,0.4165,0.1234 T0.4305,0.1215 L0.4337,0.1215 Q0.4442,0.1215,0.4518,0.1251 T0.4659,0.1294 Q0.4876,0.1319,0.5116,0.1319 T0.5622,0.141 Q0.5703,0.1439,0.5751,0.1439 Q0.5791,0.1439,0.5831,0.1423 T0.5888,0.1406 Q0.592,0.1406,0.5944,0.1412 T0.6012,0.1427 T0.6129,0.1435 Q0.6313,0.1435,0.649,0.1497 Q0.6602,0.1535,0.6667,0.1535 Q0.6715,0.1535,0.6779,0.1522 Q0.6787,0.1518,0.6795,0.1518 Q0.6827,0.1518,0.6847,0.1541 T0.6867,0.1593 Q0.6867,0.1618,0.6851,0.1634 Q0.6835,0.1655,0.6775,0.1667 T0.6598,0.169 T0.6458,0.1705 T0.6402,0.1709 Q0.6378,0.1709,0.6321,0.1705 T0.6225,0.1701 Q0.6096,0.1701,0.5968,0.1738 Q0.5823,0.1779,0.5446,0.1779 Q0.5205,0.1779,0.5116,0.1767 Q0.51,0.1763,0.5084,0.1763 Q0.5028,0.1763,0.4944,0.1796 T0.4835,0.1829 L0.4771,0.1833 T0.4659,0.1844 L0.4546,0.1858 T0.443,0.1881 T0.4337,0.1912 Q0.4321,0.1916,0.4305,0.1916 Q0.4273,0.1916,0.4209,0.1895 T0.412,0.1875 Q0.408,0.1875,0.4056,0.19 Q0.4024,0.1925,0.388,0.1925 Q0.3663,0.1925,0.3558,0.1879 Q0.3518,0.1862,0.3462,0.1862 Q0.3373,0.1862,0.3213,0.191 T0.3012,0.1962 Q0.2964,0.1966,0.2799,0.1976 T0.2494,0.1997 T0.2313,0.2024 L0.2313,0.2024 L0.2293,0.2024 L0.2261,0.2024 L0.2217,0.2024 Q0.204,0.2024,0.1851,0.2047 T0.1526,0.2136 Q0.1406,0.2198,0.1406,0.226 Q0.1406,0.2319,0.1518,0.2362 T0.1719,0.2406 Q0.1791,0.2406,0.2466,0.2497 Q0.2498,0.2501,0.2574,0.2516 T0.2711,0.2538 T0.2819,0.2547 L0.2851,0.2547 Q0.2851,0.2543,0.2859,0.2543 Q0.294,0.2543,0.3096,0.2592 T0.3285,0.2684 Q0.3317,0.2721,0.3373,0.2721 Q0.3406,0.2721,0.3462,0.2708 T0.3542,0.2696 Q0.3558,0.2696,0.3574,0.27 Q0.3679,0.2737,0.3968,0.2762 Q0.3984,0.2766,0.4004,0.2779 L0.4044,0.2804 T0.4096,0.2816 Q0.412,0.2816,0.4145,0.2808 Q0.4177,0.2804,0.4249,0.2804 Q0.4586,0.2804,0.4763,0.287 Q0.4867,0.2912,0.4972,0.2912 Q0.5004,0.2912,0.5064,0.2908 T0.5165,0.2903 Q0.5293,0.2903,0.5361,0.2922 T0.547,0.3003 L0.547,0.3011 Q0.547,0.3036,0.5414,0.3049 T0.5249,0.3067 T0.51,0.3082 Q0.5092,0.3082,0.4831,0.3111 T0.4498,0.3161 Q0.408,0.3264,0.3952,0.3264 Q0.3896,0.3264,0.3863,0.3252 Q0.3783,0.3223,0.3703,0.3223 Q0.359,0.3223,0.3494,0.3277 Q0.347,0.3293,0.343,0.3293 Q0.3414,0.3293,0.3353,0.3285 T0.3253,0.3277 T0.3181,0.3285 Q0.3149,0.3289,0.2952,0.3306 T0.2699,0.3347 Q0.2675,0.3364,0.2598,0.3372 T0.2434,0.3395 T0.2297,0.3426 L0.2205,0.3461 T0.2048,0.3523 T0.1908,0.3606 T0.1791,0.3725 Q0.1743,0.3803,0.1743,0.3845 Q0.1743,0.3874,0.1763,0.3901 T0.1827,0.3976 T0.1912,0.4073 T0.198,0.4189 T0.2032,0.4276 T0.2137,0.4326 T0.2386,0.438 Q0.2458,0.4392,0.2562,0.4392 L0.2639,0.4392 L0.2699,0.4392 Q0.2795,0.4392,0.2843,0.4405 Q0.2932,0.443,0.3092,0.443 L0.3157,0.443 L0.3213,0.443 Q0.3293,0.443,0.3458,0.4463 T0.3671,0.4525 Q0.3598,0.4558,0.3373,0.4571 Q0.3124,0.4587,0.298,0.4637 Q0.294,0.465,0.2811,0.465 L0.2703,0.465 L0.2586,0.465 Q0.241,0.465,0.2305,0.4666 Q0.2185,0.4687,0.2185,0.4728 Q0.2185,0.4745,0.2205,0.4764 T0.2241,0.4791 L0.2265,0.4803 L0.2273,0.4803 Q0.2506,0.4824,0.261,0.4824 Q0.2675,0.4824,0.2699,0.482 Q0.2699,0.4815,0.2707,0.4815 Q0.2771,0.4815,0.3124,0.4898 Q0.3173,0.4907,0.3229,0.4913 T0.3386,0.4925 T0.3542,0.4936 T0.3663,0.494 Q0.3711,0.494,0.3787,0.4936 T0.3888,0.4932 Q0.392,0.4932,0.3944,0.4936 T0.4032,0.4959 T0.4181,0.499 T0.4369,0.5006 Q0.449,0.501,0.455,0.5021 T0.4639,0.5048 T0.4675,0.5093 L0.4675,0.5097 Q0.4675,0.5106,0.4663,0.511 T0.4622,0.5116 L0.4566,0.512 T0.4486,0.5124 T0.4402,0.5127 Q0.4345,0.5131,0.4257,0.5153 T0.4096,0.5176 Q0.4064,0.5176,0.4024,0.5172 L0.3968,0.5172 Q0.3863,0.5172,0.3731,0.522 T0.359,0.5268 Q0.355,0.528,0.3317,0.5321 T0.3004,0.5388 Q0.2867,0.5433,0.2337,0.5479 Q0.2096,0.55,0.2096,0.5562 Q0.2096,0.5591,0.2145,0.5628 Q0.2193,0.5662,0.2289,0.5662 Q0.2313,0.5662,0.2373,0.5657 T0.2458,0.5653 L0.2498,0.5653 Q0.2635,0.5674,0.3124,0.5674 Q0.3261,0.5674,0.3301,0.567 L0.3317,0.567 Q0.3341,0.567,0.3394,0.568 T0.3486,0.5691 Q0.3542,0.5691,0.3606,0.5678 T0.3699,0.5666 T0.3759,0.5686 T0.3839,0.5718 T0.3908,0.573 T0.3964,0.5734 T0.4048,0.5742 T0.4165,0.5751 T0.4277,0.5757 T0.4369,0.5778 Q0.4426,0.5794,0.4538,0.5794 Q0.4586,0.5794,0.4679,0.5792 T0.4811,0.579 Q0.4924,0.579,0.4956,0.5807 Q0.502,0.584,0.5108,0.584 L0.5137,0.584 T0.5173,0.5838 L0.5205,0.5834 L0.5237,0.583 L0.5269,0.5825 T0.5305,0.5821 T0.5341,0.5819 L0.5365,0.5819 Q0.5414,0.5819,0.5562,0.5842 T0.5855,0.5865 Q0.5912,0.5865,0.5948,0.5867 T0.6012,0.5869 T0.6064,0.5873 T0.61,0.5877 T0.6133,0.5886 T0.6157,0.5896 L0.6185,0.591 T0.6217,0.5931 Q0.6265,0.5952,0.6369,0.5952 L0.6418,0.5952 L0.6466,0.5952 Q0.6723,0.5952,0.6932,0.606 Q0.698,0.608,0.7044,0.608 Q0.7084,0.608,0.7161,0.6068 T0.7261,0.6056 Q0.7309,0.6056,0.7454,0.6051 T0.7647,0.6047 Q0.7775,0.6047,0.8072,0.6101 Q0.8096,0.6105,0.812,0.6105 Q0.8177,0.6105,0.8297,0.6085 T0.8474,0.606 L0.8506,0.606 Q0.8562,0.606,0.8647,0.607 T0.8831,0.6095 T0.8964,0.6118 Q0.9036,0.6122,0.9221,0.6122 L0.9406,0.6122 L0.959,0.6122 L0.9767,0.6122 Q0.9952,0.613,0.9952,0.6172 Q0.9952,0.6176,0.9944,0.6221 Q0.9936,0.6259,0.9574,0.6259 L0.955,0.6259 L0.9526,0.6259 Q0.9478,0.6259,0.9373,0.628 T0.9205,0.63 L0.9173,0.63 Q0.9133,0.6296,0.9084,0.6296 Q0.9004,0.6296,0.8715,0.6321 Q0.8233,0.6367,0.7944,0.64 Q0.7888,0.6408,0.7839,0.6408 T0.7739,0.6402 T0.7671,0.6396 Q0.7639,0.6396,0.7622,0.64 Q0.7614,0.6404,0.759,0.6404 Q0.7574,0.6404,0.749,0.6398 T0.7357,0.6392 Q0.7261,0.6392,0.7213,0.6412 Q0.7173,0.6425,0.7032,0.6437 T0.6711,0.6458 T0.6474,0.647 Q0.645,0.6474,0.6418,0.6474 Q0.6353,0.6474,0.6277,0.6454 T0.6161,0.6433 Q0.6104,0.6433,0.6072,0.6456 T0.6,0.6479 Q0.5912,0.6479,0.5486,0.6557 Q0.5422,0.657,0.5373,0.657 Q0.5349,0.657,0.5289,0.6564 T0.5173,0.6557 L0.5124,0.6557 Q0.4996,0.6562,0.4739,0.6611 Q0.4675,0.6624,0.4398,0.6645 T0.3851,0.668 T0.3558,0.6698 Q0.355,0.6698,0.3285,0.6721 T0.2948,0.6752 Q0.2892,0.6761,0.2843,0.6786 T0.2747,0.6831 T0.2618,0.6852 Q0.253,0.6852,0.2394,0.6893 T0.2141,0.6993 T0.1968,0.7105 Q0.1944,0.713,0.1944,0.7155 Q0.1944,0.7196,0.2012,0.7229 T0.2177,0.7285 T0.2281,0.7308 Q0.2321,0.7329,0.2365,0.7339 T0.245,0.7356 T0.2514,0.7366 Q0.2522,0.737,0.2554,0.7379 T0.2614,0.7393 T0.2679,0.7406 T0.2755,0.7416 T0.2835,0.742 Q0.29,0.742,0.3048,0.7428 T0.3253,0.7437 L0.3301,0.7437 L0.3333,0.7437 Q0.3341,0.7437,0.3598,0.7466 Q0.3639,0.7474,0.3671,0.7474 T0.3759,0.7466 T0.3855,0.7457 Q0.388,0.7457,0.3904,0.7462 Q0.3984,0.7466,0.4137,0.7495 T0.4349,0.7532 T0.441,0.7557 Q0.441,0.7599,0.4289,0.7619 Q0.4257,0.7628,0.4197,0.7634 T0.4072,0.7644 T0.3984,0.7652 Q0.3968,0.7652,0.3912,0.7655 T0.3811,0.7665 T0.3719,0.7694 Q0.3695,0.7702,0.3655,0.7702 T0.3546,0.7686 T0.3462,0.7665 L0.3446,0.7665 Q0.3406,0.7665,0.3293,0.769 T0.3149,0.7715 Q0.3084,0.7715,0.2952,0.7748 T0.2763,0.781 Q0.2675,0.7847,0.2554,0.7864 Q0.253,0.7864,0.2325,0.7874 T0.2024,0.7893 Q0.2008,0.7893,0.1984,0.7897 T0.1948,0.7901 T0.1916,0.7903 T0.1888,0.7908 T0.1867,0.7914 T0.1847,0.7922 L0.1831,0.793 T0.1819,0.7943 L0.1811,0.7959 T0.1799,0.7976 Q0.1791,0.7993,0.1791,0.8001 Q0.1791,0.8034,0.1831,0.8051 T0.1932,0.8078 T0.2,0.8092 Q0.2072,0.8117,0.2257,0.8117 Q0.2337,0.8117,0.2586,0.8109 L0.2635,0.8109 Q0.2707,0.8109,0.2767,0.8117 T0.2859,0.8136 T0.2936,0.8163 T0.3012,0.8187 Q0.3068,0.82,0.3277,0.8206 T0.3526,0.8237 Q0.3582,0.8266,0.3622,0.8266 Q0.3647,0.8266,0.3687,0.8258 T0.3751,0.825 Q0.396,0.825,0.404,0.8291 Q0.408,0.8316,0.4161,0.8316 Q0.4217,0.8316,0.4353,0.8295 L0.4394,0.8295 Q0.4466,0.8295,0.4659,0.8366 Q0.4699,0.8378,0.4747,0.8378 Q0.4763,0.8378,0.4807,0.8374 T0.4884,0.837 Q0.494,0.837,0.5004,0.8382 Q0.5052,0.8391,0.5124,0.8399 Q0.5221,0.8411,0.5249,0.8422 T0.5277,0.8461 Q0.5277,0.8482,0.5233,0.849 T0.5112,0.8501 T0.4996,0.8511 Q0.4964,0.8519,0.4851,0.8523 T0.4659,0.8544 Q0.4578,0.8557,0.4402,0.8557 L0.4349,0.8557 L0.4297,0.8557 L0.4209,0.8557 Q0.408,0.8565,0.3867,0.8571 T0.3614,0.8582 Q0.3317,0.8611,0.3237,0.8611 L0.3225,0.8611 L0.3213,0.8611 Q0.2972,0.8611,0.2972,0.8681 Q0.2972,0.8714,0.3008,0.8747 T0.3044,0.8805 Q0.3044,0.881,0.3036,0.8814 Q0.3012,0.8839,0.2851,0.8839 Q0.2779,0.8839,0.2739,0.883 Q0.2723,0.8826,0.2699,0.8826 T0.2643,0.8835 T0.259,0.8853 T0.2542,0.8876 T0.249,0.8893 Q0.2386,0.8922,0.2056,0.8946 Q0.2016,0.8951,0.1916,0.898 T0.1703,0.9009 Q0.1518,0.9009,0.1337,0.9044 T0.1149,0.9146 L0.1149,0.9158 Q0.1149,0.9175,0.1157,0.9187 T0.1173,0.921 T0.1201,0.9226 T0.1233,0.9237 T0.1269,0.9245 L0.1305,0.9251 T0.1337,0.9255 L0.1357,0.9258 Q0.139,0.9262,0.1446,0.9262 T0.1542,0.9266 T0.1598,0.9282 Q0.1614,0.9303,0.1647,0.9314 T0.1739,0.9328 T0.1815,0.9336 Q0.1863,0.9345,0.1976,0.9372 T0.2145,0.9415 Q0.2225,0.9432,0.2285,0.9467 T0.2378,0.9515 Q0.2426,0.9531,0.2514,0.9531 Q0.2538,0.9531,0.2602,0.9529 T0.2707,0.9527 Q0.2763,0.9527,0.2815,0.9531 T0.2867,0.9569 T0.2811,0.9614 Q0.2434,0.9627,0.2329,0.9652 Q0.2249,0.9672,0.2241,0.9672 L0.2096,0.9668 L0.2056,0.9668 Q0.2,0.9668,0.196,0.9672 T0.1884,0.9687 T0.1815,0.9708 T0.1731,0.9737 T0.1639,0.9772 Q0.1518,0.9805,0.1285,0.9805 L0.1253,0.9805 Q0.1124,0.9805,0.1076,0.9818 Q0.1012,0.983,0.0831,0.9876 T0.0594,0.9934 Q0.049,0.9954,0.0064,0.9954 Z M0.0032,0.9979 L0.0024,0.0037 Q0.0161,0.0021,0.0289,0.0062 Q0.0337,0.0075,0.0671,0.0066 T0.1116,0.01 T0.1337,0.0166 T0.151,0.022 Q0.1582,0.0249,0.1659,0.0251 T0.1767,0.0265 Q0.1807,0.0278,0.2,0.0292 T0.2265,0.0328 Q0.2305,0.034,0.2329,0.034 T0.239,0.0326 T0.2458,0.0311 T0.253,0.0319 Q0.2578,0.0332,0.2614,0.0342 T0.2667,0.0363 T0.2723,0.0384 T0.2827,0.0406 Q0.3084,0.0448,0.3141,0.0485 Q0.3149,0.0494,0.3225,0.0494 T0.3361,0.0504 T0.3422,0.0554 T0.3357,0.0606 T0.3205,0.0618 T0.31,0.0626 Q0.3092,0.0626,0.3056,0.0659 T0.2932,0.0701 Q0.2884,0.0709,0.2843,0.0709 Q0.2811,0.0709,0.2759,0.0701 T0.2667,0.0693 Q0.2586,0.0693,0.2422,0.0718 T0.2193,0.0763 Q0.2137,0.0784,0.1831,0.079 T0.1502,0.0805 Q0.1494,0.0809,0.147,0.0809 Q0.1454,0.0809,0.1386,0.0803 T0.1277,0.0796 Q0.1173,0.0796,0.1092,0.0821 Q0.1036,0.0834,0.1036,0.0854 Q0.1036,0.0879,0.1129,0.0908 T0.1269,0.0937 Q0.1293,0.0937,0.1558,0.0991 T0.1863,0.1045 Q0.2016,0.1045,0.2193,0.1087 Q0.2225,0.1091,0.2249,0.1091 Q0.2289,0.1091,0.2357,0.1076 T0.2482,0.1054 Q0.2506,0.1049,0.2546,0.1049 Q0.2699,0.1049,0.2924,0.1085 T0.3213,0.1165 Q0.3253,0.119,0.3301,0.119 Q0.3325,0.119,0.3446,0.1161 T0.3687,0.1124 Q0.3831,0.1112,0.3863,0.1112 T0.3908,0.1118 T0.3936,0.1145 T0.3984,0.1186 Q0.4048,0.1228,0.408,0.1228 Q0.4096,0.1228,0.4161,0.1213 T0.4305,0.1195 L0.4337,0.1195 Q0.4426,0.1195,0.4474,0.1211 T0.4566,0.1246 T0.4667,0.1273 Q0.4876,0.1298,0.5116,0.1298 Q0.5365,0.1298,0.5631,0.1389 Q0.5703,0.1414,0.5751,0.1414 Q0.5783,0.1414,0.5819,0.1398 T0.5888,0.1381 Q0.5928,0.1381,0.5984,0.1398 T0.6129,0.1414 Q0.6321,0.1414,0.6498,0.1477 Q0.661,0.1514,0.6667,0.1514 Q0.6707,0.1514,0.6771,0.1501 Q0.6787,0.1497,0.6795,0.1497 Q0.6835,0.1497,0.6863,0.1526 T0.6892,0.1593 Q0.6892,0.1626,0.6876,0.1647 Q0.6851,0.1672,0.6799,0.1686 T0.6695,0.1705 T0.6566,0.1715 T0.6458,0.1725 Q0.6434,0.173,0.6402,0.173 Q0.6378,0.173,0.6317,0.1727 T0.6225,0.1725 Q0.6096,0.1725,0.5984,0.1759 Q0.5823,0.1804,0.5454,0.1804 Q0.5205,0.1804,0.5116,0.1788 L0.5084,0.1788 Q0.5036,0.1788,0.4956,0.1819 T0.4843,0.185 Q0.4434,0.1887,0.4353,0.1929 Q0.4321,0.1945,0.4289,0.1945 T0.4197,0.1922 T0.4112,0.19 T0.4072,0.1912 Q0.4032,0.1949,0.388,0.1949 Q0.3663,0.1949,0.3542,0.19 Q0.351,0.1883,0.3462,0.1883 Q0.3406,0.1883,0.3321,0.1906 T0.3153,0.1954 T0.302,0.1983 Q0.2972,0.1991,0.2859,0.1997 T0.2643,0.201 T0.245,0.2024 T0.2337,0.2041 Q0.2321,0.2045,0.2181,0.2045 T0.1851,0.207 T0.1542,0.2157 Q0.143,0.2211,0.143,0.226 Q0.143,0.2314,0.153,0.2348 T0.1719,0.2381 Q0.1791,0.2381,0.2474,0.2476 Q0.2506,0.248,0.2558,0.2489 T0.2651,0.2505 T0.2739,0.252 T0.2819,0.2526 Q0.2835,0.2526,0.2851,0.2522 L0.2859,0.2522 Q0.2948,0.2522,0.3104,0.2574 T0.3309,0.2671 Q0.3333,0.2696,0.3365,0.2696 Q0.339,0.2696,0.3442,0.2684 T0.3526,0.2671 T0.3582,0.2679 Q0.3687,0.2717,0.3968,0.2742 Q0.4,0.2746,0.4036,0.2771 T0.4096,0.2796 Q0.4112,0.2796,0.4137,0.2787 Q0.4169,0.2779,0.4257,0.2779 Q0.4594,0.2779,0.4779,0.2849 Q0.4876,0.2891,0.4972,0.2891 Q0.4996,0.2891,0.506,0.2887 T0.5165,0.2883 Q0.5253,0.2883,0.5305,0.2889 T0.541,0.292 T0.5494,0.299 L0.5494,0.3015 Q0.5494,0.3036,0.5466,0.3051 T0.5386,0.3073 T0.5285,0.3086 T0.5181,0.3094 T0.5108,0.3102 Q0.5068,0.3107,0.494,0.3121 L0.4683,0.315 T0.4506,0.3181 Q0.449,0.3181,0.4426,0.32 T0.4313,0.3229 T0.4197,0.3256 T0.4064,0.3281 T0.3952,0.3289 Q0.3888,0.3289,0.3855,0.3273 Q0.3783,0.3243,0.3703,0.3243 Q0.3598,0.3243,0.351,0.3297 Q0.3478,0.3314,0.3422,0.3314 Q0.3398,0.3314,0.3337,0.3306 T0.3245,0.3297 T0.3189,0.3306 Q0.3149,0.3314,0.2956,0.3328 T0.2715,0.3368 Q0.2691,0.338,0.2635,0.3391 T0.2522,0.3407 T0.2406,0.3424 T0.2313,0.3447 Q0.2305,0.3447,0.2213,0.348 T0.206,0.354 T0.1924,0.3621 T0.1815,0.3733 Q0.1767,0.3816,0.1767,0.3849 Q0.1767,0.387,0.1783,0.3893 T0.1847,0.3961 T0.1936,0.4063 T0.2004,0.4181 T0.2052,0.4264 T0.2145,0.4309 T0.2386,0.4359 Q0.2458,0.4372,0.2554,0.4372 Q0.2578,0.4372,0.2627,0.437 T0.2699,0.4367 Q0.2795,0.4367,0.2851,0.4384 Q0.294,0.4409,0.3092,0.4409 Q0.3116,0.4409,0.3157,0.4407 T0.3213,0.4405 Q0.3301,0.4405,0.3466,0.444 T0.3687,0.4509 Q0.3703,0.4517,0.3703,0.4525 Q0.3703,0.4575,0.3373,0.4596 Q0.3133,0.4608,0.2988,0.4658 Q0.294,0.4674,0.2803,0.4674 Q0.2763,0.4674,0.2687,0.4672 T0.257,0.467 Q0.2402,0.467,0.2313,0.4687 Q0.2209,0.4708,0.2209,0.4737 Q0.2209,0.4741,0.2213,0.4749 T0.2229,0.4764 L0.2249,0.4774 T0.2265,0.4778 L0.2273,0.4782 Q0.2498,0.4803,0.2618,0.4803 Q0.2667,0.4803,0.2691,0.4799 Q0.2699,0.4795,0.2715,0.4795 Q0.2779,0.4795,0.3133,0.4873 Q0.3181,0.4886,0.3233,0.4892 T0.3386,0.4905 T0.3542,0.4915 T0.3655,0.4919 Q0.3703,0.4919,0.3779,0.4915 T0.3888,0.4911 T0.3952,0.4915 Q0.3976,0.4919,0.4008,0.4927 L0.4072,0.4944 T0.4149,0.4961 T0.4249,0.4975 T0.4369,0.4985 Q0.449,0.499,0.4554,0.5 T0.4651,0.5031 T0.4699,0.5085 Q0.4707,0.5093,0.4707,0.5097 Q0.4707,0.5114,0.4687,0.5124 T0.4631,0.5139 T0.4562,0.5145 T0.4478,0.5147 L0.4402,0.5147 Q0.4353,0.5151,0.4265,0.5174 T0.4096,0.5197 L0.4024,0.5197 Q0.4,0.5193,0.3968,0.5193 Q0.3896,0.5193,0.3831,0.5209 T0.3703,0.5253 T0.3598,0.5288 Q0.3558,0.5301,0.3321,0.5342 T0.302,0.5409 Q0.2876,0.5454,0.2337,0.55 Q0.2112,0.5521,0.2112,0.5558 Q0.2112,0.5574,0.2161,0.5612 Q0.2201,0.5637,0.2281,0.5637 Q0.2305,0.5637,0.2361,0.5633 T0.2442,0.5628 Q0.2474,0.5628,0.2498,0.5633 Q0.2635,0.5653,0.3133,0.5653 Q0.3261,0.5653,0.3301,0.5649 L0.3325,0.5649 Q0.3349,0.5649,0.3402,0.5657 T0.3494,0.5666 Q0.3542,0.5666,0.3598,0.5657 Q0.3663,0.5645,0.3695,0.5645 Q0.3735,0.5645,0.3775,0.5666 T0.3847,0.5695 Q0.3888,0.5707,0.3912,0.5709 T0.3968,0.5711 T0.4048,0.572 Q0.4096,0.5724,0.4165,0.5726 T0.4281,0.5734 T0.4378,0.5757 Q0.4418,0.5774,0.4522,0.5774 Q0.4562,0.5774,0.4655,0.5769 T0.4795,0.5765 Q0.4932,0.5765,0.4972,0.579 Q0.5028,0.5819,0.51,0.5819 Q0.5141,0.5819,0.5221,0.5809 T0.5341,0.5798 L0.5373,0.5798 Q0.5422,0.5798,0.557,0.5821 T0.5855,0.5844 L0.5936,0.5844 L0.5992,0.5844 T0.604,0.5848 T0.6076,0.5852 T0.6108,0.5859 T0.6137,0.5865 T0.6161,0.5873 T0.6181,0.5881 T0.6209,0.5896 L0.6233,0.591 Q0.6265,0.5927,0.6353,0.5927 L0.6402,0.5927 L0.645,0.5927 Q0.6723,0.5927,0.6948,0.6039 Q0.6988,0.606,0.7036,0.606 Q0.7076,0.606,0.7153,0.6045 T0.7261,0.6031 Q0.7309,0.6031,0.7454,0.6027 T0.7647,0.6022 Q0.7783,0.6022,0.808,0.608 L0.812,0.608 Q0.8169,0.608,0.8293,0.6062 T0.8474,0.6039 L0.8506,0.6039 Q0.857,0.6039,0.8655,0.6049 T0.8835,0.6074 T0.8972,0.6093 Q0.9036,0.6101,0.9213,0.6101 L0.9398,0.6101 L0.959,0.6101 L0.9767,0.6101 Q0.9976,0.6109,0.9976,0.6176 Q0.9976,0.6188,0.9968,0.6226 Q0.9952,0.6284,0.9671,0.6284 L0.959,0.6284 L0.9526,0.6284 Q0.9486,0.6284,0.9382,0.6302 T0.9205,0.6321 L0.9173,0.6321 Q0.9133,0.6317,0.9092,0.6317 Q0.9012,0.6317,0.8715,0.6346 Q0.8233,0.6387,0.7944,0.6421 Q0.7888,0.6429,0.7831,0.6429 Q0.7783,0.6429,0.7731,0.6425 T0.7663,0.6421 L0.7622,0.6421 Q0.7614,0.6425,0.7586,0.6425 T0.7474,0.6421 T0.7349,0.6416 Q0.7261,0.6416,0.7221,0.6429 Q0.7173,0.645,0.7032,0.646 T0.6711,0.6479 T0.6482,0.6491 Q0.645,0.6495,0.6418,0.6495 Q0.6353,0.6495,0.6273,0.6474 T0.6161,0.6454 Q0.612,0.6454,0.6088,0.6477 T0.6,0.6499 Q0.5912,0.6499,0.5494,0.6578 Q0.5422,0.6591,0.5373,0.6591 Q0.5341,0.6591,0.5281,0.6584 T0.5173,0.6578 L0.5124,0.6578 Q0.5004,0.6582,0.4747,0.6632 Q0.4675,0.6649,0.4398,0.6667 T0.3851,0.6703 T0.3566,0.6719 Q0.3534,0.6723,0.3406,0.6734 T0.3141,0.6757 T0.2948,0.6773 Q0.2908,0.6781,0.2819,0.6829 T0.2618,0.6877 Q0.2482,0.6877,0.2273,0.6958 T0.1992,0.7117 Q0.1976,0.7138,0.1976,0.7155 Q0.1976,0.7188,0.2032,0.7213 T0.2181,0.7258 T0.2289,0.7292 Q0.2337,0.7308,0.2378,0.7316 L0.2458,0.7333 T0.2522,0.7345 Q0.2747,0.7399,0.2835,0.7399 Q0.29,0.7399,0.3048,0.7408 T0.3253,0.7416 Q0.3277,0.7416,0.3297,0.7414 T0.3341,0.7412 L0.3598,0.7445 Q0.3639,0.7449,0.3663,0.7449 Q0.3695,0.7449,0.3751,0.7443 T0.3855,0.7437 L0.3904,0.7437 Q0.3984,0.7441,0.4141,0.7472 T0.4353,0.7507 Q0.4434,0.752,0.4434,0.7553 Q0.4434,0.7578,0.439,0.7605 T0.4297,0.764 Q0.4257,0.7648,0.4201,0.7655 T0.4076,0.7665 T0.3984,0.7673 Q0.3968,0.7673,0.3912,0.7677 T0.3815,0.7688 T0.3735,0.771 T0.3655,0.7727 Q0.3606,0.7727,0.3534,0.7708 T0.3458,0.769 L0.3446,0.769 Q0.3414,0.769,0.3297,0.7713 T0.3149,0.7735 Q0.3092,0.7735,0.296,0.7771 T0.2771,0.7831 Q0.2683,0.7872,0.2554,0.7885 Q0.253,0.7889,0.2325,0.7897 T0.2032,0.7914 Q0.2008,0.7918,0.198,0.792 T0.194,0.7924 T0.1912,0.7928 T0.1888,0.793 T0.1867,0.7934 T0.1851,0.7943 T0.1843,0.7953 T0.1835,0.7968 T0.1823,0.7984 T0.1815,0.8001 Q0.1815,0.8022,0.1847,0.8032 T0.1932,0.8053 T0.2008,0.8071 Q0.2072,0.8092,0.2265,0.8092 Q0.2361,0.8092,0.2586,0.8088 L0.2635,0.8088 Q0.2731,0.8088,0.2795,0.8098 T0.2928,0.8134 T0.302,0.8167 Q0.306,0.8179,0.3277,0.8183 T0.3542,0.8221 Q0.359,0.8246,0.3622,0.8246 Q0.3639,0.8246,0.3675,0.8237 T0.3751,0.8229 Q0.3968,0.8229,0.4048,0.8275 Q0.4088,0.8291,0.4161,0.8291 Q0.4225,0.8291,0.4353,0.8275 Q0.4369,0.827,0.4394,0.827 Q0.4474,0.827,0.4675,0.8345 Q0.4707,0.8358,0.4739,0.8358 Q0.4755,0.8358,0.4799,0.8353 T0.4876,0.8349 Q0.494,0.8349,0.5012,0.8362 L0.5076,0.837 T0.5133,0.8376 T0.5181,0.8382 T0.5221,0.8391 L0.5253,0.8399 T0.5277,0.8409 L0.5293,0.8422 T0.5301,0.8438 L0.5301,0.8461 Q0.5301,0.8499,0.5249,0.8511 T0.5112,0.8526 T0.5004,0.8532 Q0.4964,0.854,0.4851,0.8546 T0.4667,0.8565 Q0.4578,0.8577,0.441,0.8577 L0.4345,0.8577 L0.4289,0.8577 L0.4209,0.8577 Q0.4153,0.8582,0.4088,0.8586 T0.3968,0.8592 T0.3855,0.8594 T0.3755,0.8596 T0.3675,0.86 T0.3622,0.8602 Q0.3317,0.8635,0.3237,0.8635 Q0.2996,0.8635,0.2996,0.8681 Q0.2996,0.8698,0.3032,0.8733 T0.3068,0.8797 L0.3068,0.8822 Q0.3052,0.8859,0.2859,0.8859 Q0.2787,0.8859,0.2739,0.8851 L0.2699,0.8851 Q0.2659,0.8851,0.259,0.888 T0.2498,0.8913 Q0.2394,0.8946,0.2056,0.8971 Q0.2032,0.8971,0.1928,0.9002 T0.1703,0.9034 Q0.1526,0.9034,0.1353,0.9067 T0.1173,0.915 L0.1173,0.9158 Q0.1173,0.9166,0.1177,0.9175 T0.1189,0.9191 T0.1205,0.9204 T0.1229,0.9212 T0.1257,0.922 T0.1285,0.9226 T0.1309,0.9231 T0.1337,0.9235 T0.1365,0.9237 L0.1446,0.9237 T0.1554,0.9243 T0.1614,0.9268 T0.1659,0.9293 T0.1743,0.9303 T0.1823,0.9316 Q0.1863,0.932,0.1912,0.9332 T0.2028,0.9361 T0.2153,0.939 Q0.2233,0.9411,0.2297,0.9448 T0.2386,0.9494 Q0.2426,0.9506,0.2506,0.9506 Q0.253,0.9506,0.2594,0.9504 T0.2699,0.9502 Q0.2763,0.9502,0.2819,0.9511 Q0.2851,0.9511,0.2871,0.9529 T0.2892,0.9573 Q0.2892,0.9627,0.2811,0.9635 Q0.2434,0.9652,0.2337,0.9672 Q0.2257,0.9693,0.2241,0.9693 Q0.2217,0.9693,0.2096,0.9689 L0.2056,0.9689 Q0.1976,0.9689,0.1924,0.9699 T0.1787,0.9741 L0.1647,0.9793 Q0.1518,0.983,0.1285,0.983 L0.1261,0.983 L0.1237,0.983 Q0.1124,0.983,0.1076,0.9838 Q0.102,0.9851,0.0839,0.9896 T0.0602,0.9954 T0.0406,0.9971 T0.0153,0.9979 L0.0032,0.9979 Z",type:0}},"\uE0CA":{type:5,data:{d:"M0.9992,0.998 Q0.9992,1,0.9968,1 Q0.9521,1,0.9392,0.998 Q0.9335,0.997,0.9152,0.9921 T0.8913,0.9862 Q0.8873,0.9852,0.8783,0.9852 L0.8747,0.9852 L0.871,0.9852 Q0.8483,0.9852,0.8345,0.9812 Q0.8289,0.9792,0.8228,0.9773 T0.8135,0.9743 T0.8054,0.9723 T0.7948,0.9713 L0.7908,0.9713 L0.777,0.9713 T0.7656,0.9693 Q0.7616,0.9683,0.7498,0.9674 T0.7283,0.9664 L0.7186,0.9654 Q0.708,0.9644,0.708,0.9575 Q0.708,0.9545,0.7109,0.952 T0.7178,0.9486 L0.7315,0.9486 L0.7417,0.9486 L0.7502,0.9486 Q0.7575,0.9486,0.7599,0.9476 Q0.7616,0.9466,0.7685,0.9426 T0.7843,0.9377 Q0.7899,0.9357,0.8009,0.9332 T0.8175,0.9298 Q0.82,0.9288,0.8228,0.9283 T0.8277,0.9278 T0.8313,0.9273 T0.8341,0.9263 T0.8362,0.9258 Q0.8402,0.9219,0.854,0.9219 L0.8569,0.9219 L0.8597,0.9219 L0.8637,0.9219 Q0.88,0.9199,0.88,0.9159 L0.88,0.9149 Q0.88,0.913,0.8719,0.911 T0.852,0.9075 T0.8297,0.906 Q0.8224,0.906,0.8167,0.905 T0.8074,0.9031 T0.8001,0.9006 T0.794,0.8991 Q0.7599,0.8971,0.7494,0.8942 Q0.7461,0.8932,0.7397,0.8902 T0.7299,0.8872 L0.7267,0.8872 Q0.721,0.8882,0.7121,0.8882 Q0.6926,0.8882,0.691,0.8833 L0.691,0.8803 Q0.691,0.8773,0.6922,0.8749 T0.6955,0.8704 L0.6975,0.8684 Q0.6926,0.8655,0.6764,0.8655 Q0.6683,0.8655,0.6375,0.8625 Q0.6358,0.8625,0.629,0.862 T0.6148,0.8615 T0.5973,0.861 T0.5791,0.8605 L0.5718,0.8605 L0.5661,0.8605 L0.5596,0.8605 Q0.5426,0.8605,0.5337,0.8586 Q0.5264,0.8576,0.515,0.8571 T0.4996,0.8556 Q0.498,0.8556,0.4947,0.8551 T0.4882,0.8546 T0.4809,0.8541 T0.474,0.8531 T0.4692,0.8506 T0.4672,0.8467 Q0.4672,0.8437,0.468,0.8422 T0.4704,0.8398 T0.4736,0.8383 T0.4781,0.8368 T0.4838,0.8358 T0.4911,0.8353 T0.4988,0.8338 Q0.5069,0.8328,0.5142,0.8328 Q0.5174,0.8328,0.5215,0.8333 T0.5264,0.8338 Q0.5296,0.8338,0.532,0.8328 Q0.5523,0.8249,0.5604,0.8249 L0.5653,0.8249 Q0.5775,0.8269,0.5848,0.8269 Q0.5912,0.8269,0.5937,0.8259 Q0.6026,0.821,0.6253,0.821 Q0.6294,0.821,0.6334,0.822 T0.6383,0.8229 Q0.6399,0.8229,0.644,0.82 Q0.6504,0.817,0.6723,0.816 T0.6975,0.814 Q0.6999,0.814,0.7048,0.8121 T0.7129,0.8091 T0.7226,0.8071 T0.7372,0.8061 L0.7421,0.8061 Q0.7624,0.8071,0.7721,0.8071 Q0.7924,0.8071,0.7981,0.8051 Q0.8021,0.8032,0.807,0.8027 T0.8135,0.8017 T0.8151,0.8002 L0.8151,0.7992 Q0.8143,0.7962,0.8127,0.7957 T0.8045,0.7943 Q0.7997,0.7943,0.7964,0.7933 Q0.7883,0.7933,0.7676,0.7923 T0.7437,0.7903 Q0.7307,0.7893,0.7218,0.7844 Q0.7194,0.7834,0.7141,0.7819 L0.7036,0.7789 T0.693,0.7765 T0.6853,0.7755 Q0.6805,0.7755,0.6691,0.773 T0.6553,0.7705 Q0.6545,0.7705,0.6545,0.7715 Q0.6537,0.7715,0.65,0.7725 T0.6423,0.774 T0.635,0.7745 Q0.6294,0.7745,0.6257,0.773 T0.618,0.771 T0.6083,0.77 T0.601,0.7695 Q0.5985,0.7695,0.5921,0.769 T0.5795,0.7676 T0.5702,0.7666 Q0.5653,0.7656,0.5596,0.7616 T0.5539,0.7547 Q0.5539,0.7498,0.5645,0.7488 Q0.5693,0.7478,0.5852,0.7448 T0.6099,0.7418 L0.6148,0.7418 Q0.6196,0.7418,0.6253,0.7423 T0.6338,0.7428 L0.6399,0.7428 Q0.6431,0.7418,0.6488,0.7409 T0.6586,0.7394 T0.6659,0.7389 L0.6707,0.7389 Q0.6723,0.7399,0.6748,0.7399 Q0.6796,0.7399,0.6946,0.7389 T0.7161,0.7379 Q0.7251,0.7379,0.7478,0.7319 Q0.7494,0.7319,0.7539,0.7315 T0.762,0.73 T0.7697,0.727 T0.7818,0.723 T0.7948,0.7196 T0.7997,0.7151 Q0.7997,0.7141,0.7989,0.7132 Q0.7924,0.7062,0.7717,0.6978 T0.738,0.6894 Q0.7267,0.6894,0.717,0.6845 T0.7048,0.6795 Q0.6975,0.6785,0.6711,0.6766 T0.6431,0.6746 Q0.6415,0.6736,0.6144,0.6721 T0.5596,0.6686 T0.5247,0.6657 Q0.4996,0.6607,0.4874,0.6597 L0.4834,0.6597 Q0.4785,0.6597,0.4724,0.6607 T0.4631,0.6617 Q0.4574,0.6617,0.4501,0.6597 Q0.4088,0.6518,0.4006,0.6518 Q0.3933,0.6518,0.3901,0.6499 T0.3844,0.6479 T0.3739,0.6499 T0.3585,0.6518 L0.352,0.6518 Q0.3471,0.6508,0.335,0.6503 T0.3122,0.6494 T0.2912,0.6479 T0.2766,0.6449 Q0.2733,0.6439,0.2668,0.6439 Q0.2628,0.6439,0.2543,0.6444 T0.2425,0.6449 T0.2368,0.6439 L0.2344,0.6439 Q0.2336,0.6439,0.2283,0.6444 T0.2182,0.6449 Q0.2117,0.6449,0.2052,0.6439 Q0.1768,0.6409,0.1281,0.637 Q0.0989,0.634,0.0916,0.634 L0.0835,0.634 L0.0795,0.634 Q0.0722,0.634,0.0616,0.632 T0.0479,0.6301 Q0.0462,0.6301,0.0406,0.6306 T0.0308,0.6311 Q0.0032,0.6311,0.0008,0.6231 Q0,0.6202,0,0.6182 Q0,0.6083,0.0227,0.6083 Q0.03,0.6073,0.0422,0.6073 Q0.0487,0.6073,0.0608,0.6078 T0.0787,0.6083 Q0.0973,0.6083,0.103,0.6073 Q0.1062,0.6063,0.1131,0.6053 T0.1253,0.6039 T0.1375,0.6024 T0.1492,0.6014 L0.1533,0.6014 Q0.1598,0.6024,0.1723,0.6044 T0.189,0.6063 Q0.1906,0.6063,0.1922,0.6053 Q0.2214,0.6004,0.236,0.6004 Q0.2409,0.6004,0.2551,0.6009 T0.2741,0.6014 Q0.2782,0.6014,0.2859,0.6024 T0.2968,0.6034 Q0.3009,0.6034,0.3041,0.6024 Q0.3277,0.5905,0.356,0.5905 L0.3613,0.5905 L0.3666,0.5905 Q0.3731,0.5905,0.3755,0.5895 Q0.382,0.5856,0.3844,0.5846 T0.3938,0.5831 T0.4144,0.5826 T0.4428,0.5801 T0.4631,0.5776 L0.4663,0.5776 Q0.4704,0.5776,0.4785,0.5786 T0.4899,0.5796 Q0.4964,0.5796,0.5012,0.5767 Q0.5069,0.5737,0.5223,0.5737 Q0.5272,0.5737,0.5369,0.5742 T0.5499,0.5747 Q0.558,0.5747,0.5612,0.5737 Q0.5661,0.5717,0.5714,0.5712 T0.5835,0.5702 T0.5945,0.5692 T0.6018,0.5687 L0.6062,0.5687 T0.6095,0.5682 T0.6148,0.5678 Q0.6172,0.5668,0.6196,0.5653 T0.6245,0.5633 T0.631,0.5628 T0.6407,0.5638 T0.6504,0.5648 T0.6594,0.5638 T0.6675,0.5628 L0.6707,0.5628 L0.6861,0.5628 Q0.7364,0.5628,0.7494,0.5608 L0.7567,0.5608 L0.7652,0.5608 L0.7729,0.5608 Q0.7794,0.5608,0.7818,0.5589 Q0.7851,0.5569,0.7859,0.5559 Q0.7835,0.5539,0.7656,0.5519 Q0.7121,0.547,0.6975,0.543 Q0.6934,0.541,0.6853,0.5396 L0.6691,0.5366 T0.6525,0.5336 T0.6391,0.5312 Q0.6367,0.5302,0.6245,0.5257 T0.6034,0.5213 L0.5977,0.5213 Q0.5945,0.5223,0.5904,0.5223 Q0.5839,0.5223,0.5787,0.5208 T0.5685,0.5183 T0.5596,0.5173 Q0.558,0.5173,0.5552,0.5168 T0.5495,0.5163 L0.5434,0.5163 T0.5373,0.5158 T0.532,0.5148 T0.5284,0.5129 T0.5272,0.5104 L0.5272,0.5074 Q0.5304,0.5015,0.5377,0.499 T0.5629,0.4965 Q0.5734,0.4955,0.5811,0.4946 T0.5953,0.4916 T0.605,0.4896 Q0.6083,0.4886,0.6123,0.4886 Q0.6148,0.4886,0.6225,0.4891 T0.635,0.4896 L0.6456,0.4896 Q0.6837,0.4857,0.6861,0.4857 Q0.7226,0.4768,0.7283,0.4768 Q0.7307,0.4768,0.732,0.4773 T0.7372,0.4777 Q0.7502,0.4777,0.7721,0.4758 Q0.7753,0.4748,0.777,0.4738 Q0.7745,0.4718,0.768,0.4708 Q0.7599,0.4688,0.7445,0.4688 Q0.7405,0.4688,0.7324,0.4693 T0.721,0.4698 Q0.7056,0.4698,0.6999,0.4679 Q0.6861,0.4629,0.6626,0.4619 Q0.6586,0.4609,0.6533,0.4604 T0.6419,0.459 T0.6314,0.456 T0.6269,0.452 Q0.6269,0.451,0.6302,0.4491 Q0.6358,0.4451,0.6525,0.4416 T0.6788,0.4382 L0.6845,0.4382 L0.6902,0.4382 Q0.7064,0.4382,0.7145,0.4362 Q0.7202,0.4342,0.7307,0.4342 L0.7356,0.4342 L0.7409,0.4342 L0.7453,0.4342 Q0.7543,0.4342,0.7607,0.4332 Q0.7778,0.4313,0.7847,0.4288 T0.7932,0.4248 T0.7972,0.4169 T0.8045,0.4045 L0.8094,0.3986 T0.8135,0.3942 L0.8167,0.3912 T0.8191,0.3887 T0.8204,0.3867 T0.8208,0.3848 Q0.8208,0.3818,0.8167,0.3739 Q0.8127,0.3689,0.8054,0.3635 T0.7924,0.3556 T0.7778,0.3497 T0.768,0.3462 Q0.764,0.3442,0.7478,0.3427 T0.7267,0.3383 Q0.7234,0.3363,0.7044,0.3348 T0.6805,0.3323 L0.6764,0.3323 T0.6679,0.3328 T0.6586,0.3333 Q0.6521,0.3333,0.648,0.3314 Q0.6391,0.3264,0.6294,0.3264 Q0.6229,0.3264,0.6156,0.3294 Q0.6115,0.3304,0.6042,0.3304 Q0.5977,0.3304,0.5888,0.3289 T0.5738,0.3264 T0.5584,0.3225 L0.5491,0.3195 Q0.5418,0.3185,0.5162,0.3155 T0.4895,0.3121 T0.4826,0.3116 T0.4716,0.3111 T0.4607,0.3096 T0.4513,0.3066 T0.4477,0.3017 Q0.4477,0.2997,0.4485,0.2977 Q0.4526,0.2898,0.4611,0.2878 T0.4842,0.2859 Q0.4882,0.2859,0.4943,0.2864 T0.5028,0.2868 Q0.5118,0.2868,0.5215,0.2829 Q0.5401,0.276,0.5734,0.276 Q0.5831,0.276,0.5872,0.277 L0.5904,0.277 T0.5949,0.2745 T0.6034,0.272 Q0.631,0.269,0.6407,0.2661 Q0.6448,0.2641,0.6488,0.2641 T0.6573,0.2656 T0.6634,0.2671 Q0.6659,0.2671,0.6675,0.2651 Q0.6723,0.2601,0.6886,0.2552 T0.7137,0.2502 L0.7153,0.2502 L0.7178,0.2502 Q0.7218,0.2502,0.7279,0.2493 T0.7417,0.2468 T0.7526,0.2453 Q0.8208,0.2354,0.8281,0.2354 Q0.8337,0.2354,0.8394,0.2344 T0.8496,0.2315 T0.854,0.2265 Q0.854,0.2216,0.8443,0.2176 Q0.8354,0.2127,0.8216,0.2102 T0.7972,0.2072 T0.777,0.2067 T0.7648,0.2057 Q0.7632,0.2047,0.7498,0.2038 T0.7202,0.2018 T0.6983,0.1998 Q0.6918,0.1998,0.676,0.1949 T0.6537,0.1899 Q0.6496,0.1899,0.6472,0.1919 Q0.6342,0.1968,0.6123,0.1968 Q0.5961,0.1968,0.5912,0.1929 Q0.5904,0.1919,0.5892,0.1919 T0.5823,0.1944 T0.5722,0.1968 T0.5637,0.1949 Q0.5556,0.1909,0.5158,0.1869 Q0.5109,0.1869,0.5032,0.1835 T0.4915,0.18 Q0.4907,0.18,0.4891,0.181 Q0.4793,0.182,0.455,0.182 Q0.4177,0.182,0.4015,0.1771 Q0.3901,0.1741,0.3779,0.1741 Q0.3747,0.1741,0.369,0.1746 T0.3609,0.1751 Q0.3569,0.1751,0.3536,0.1741 Q0.3512,0.1741,0.3459,0.1736 T0.3358,0.1726 T0.3256,0.1716 T0.3167,0.1696 T0.3106,0.1662 Q0.3082,0.1632,0.3082,0.1592 Q0.3082,0.1543,0.3114,0.1508 T0.3204,0.1474 L0.3236,0.1474 Q0.3301,0.1494,0.3333,0.1494 Q0.339,0.1494,0.3496,0.1454 Q0.3674,0.1385,0.3869,0.1385 Q0.395,0.1385,0.4011,0.137 T0.4116,0.1355 T0.4197,0.1375 T0.425,0.1395 Q0.429,0.1395,0.4355,0.1365 Q0.4631,0.1266,0.4882,0.1266 Q0.5126,0.1266,0.5337,0.1246 Q0.5369,0.1246,0.5458,0.1207 T0.5661,0.1167 L0.5693,0.1167 Q0.5791,0.1177,0.5852,0.1187 T0.5921,0.1197 Q0.5945,0.1197,0.6002,0.1167 Q0.6026,0.1147,0.605,0.1123 T0.6091,0.1093 T0.6156,0.1088 T0.6318,0.1098 Q0.6456,0.1108,0.6569,0.1137 T0.6707,0.1167 Q0.674,0.1167,0.6772,0.1147 Q0.6821,0.1108,0.6946,0.1083 T0.721,0.1044 T0.7453,0.1029 L0.7526,0.1029 Q0.7583,0.1039,0.7652,0.1053 T0.7753,0.1068 Q0.7778,0.1068,0.7802,0.1058 Q0.7981,0.1019,0.8143,0.1019 Q0.8175,0.1019,0.8439,0.0964 T0.8735,0.091 Q0.8759,0.091,0.8836,0.089 T0.8938,0.0851 Q0.8929,0.0841,0.8905,0.0841 Q0.8832,0.0821,0.8735,0.0821 Q0.8694,0.0821,0.8629,0.0826 T0.854,0.0831 Q0.8508,0.0831,0.8491,0.0821 Q0.8475,0.0821,0.8171,0.0811 T0.7802,0.0781 T0.7571,0.0737 T0.7332,0.0712 Q0.7299,0.0712,0.7247,0.0717 T0.7161,0.0722 L0.7064,0.0722 Q0.7032,0.0712,0.7003,0.0707 T0.6959,0.0692 T0.693,0.0678 T0.6914,0.0663 T0.6902,0.0648 T0.689,0.0643 L0.6869,0.0643 L0.6845,0.0643 L0.6821,0.0643 Q0.6553,0.0643,0.6553,0.0554 T0.6796,0.0465 L0.6813,0.0465 L0.6845,0.0465 Q0.6918,0.0425,0.717,0.0376 Q0.7226,0.0366,0.7267,0.0356 T0.7324,0.0336 T0.7376,0.0317 T0.747,0.0297 Q0.7518,0.0287,0.7551,0.0287 T0.762,0.0297 T0.768,0.0307 L0.7729,0.0307 Q0.7802,0.0277,0.7997,0.0267 T0.8224,0.0237 Q0.8273,0.0227,0.8341,0.0223 T0.8475,0.0193 T0.8654,0.0143 T0.8873,0.0079 Q0.9002,0.003,0.9331,0.004 T0.97,0.004 Q0.9838,0,0.9976,0.001 Q1,0.001,1,0.003 Z M0.9935,0.996 L0.9951,0.0049 Q0.9822,0.0049,0.9716,0.0079 Q0.9659,0.0099,0.9327,0.0089 T0.8897,0.0119 Q0.8775,0.0158,0.8666,0.0183 T0.85,0.0237 Q0.8418,0.0267,0.8341,0.0272 T0.8248,0.0277 Q0.82,0.0297,0.8001,0.0312 T0.7745,0.0346 Q0.7697,0.0356,0.7664,0.0356 Q0.764,0.0356,0.7603,0.0341 T0.7534,0.0326 Q0.751,0.0326,0.7478,0.0336 Q0.7429,0.0346,0.7397,0.0356 T0.7344,0.0376 T0.7283,0.0401 T0.7178,0.0425 Q0.6926,0.0465,0.6878,0.0495 Q0.6845,0.0514,0.6764,0.0514 L0.6723,0.0514 L0.6691,0.0514 Q0.6602,0.0514,0.6602,0.0554 Q0.6602,0.0574,0.6659,0.0579 T0.6796,0.0589 T0.691,0.0603 T0.6967,0.0643 T0.7072,0.0673 Q0.7121,0.0682,0.7153,0.0682 T0.7238,0.0678 T0.7332,0.0673 Q0.7413,0.0673,0.7579,0.0692 T0.7818,0.0742 Q0.7867,0.0752,0.8171,0.0762 T0.8508,0.0781 L0.852,0.0781 T0.8601,0.0776 T0.8719,0.0772 Q0.8832,0.0772,0.8921,0.0791 Q0.8994,0.0811,0.8994,0.0841 T0.8933,0.0895 T0.8812,0.094 T0.8735,0.0959 T0.8451,0.1014 T0.8143,0.1068 Q0.7989,0.1068,0.7818,0.1098 Q0.7778,0.1108,0.7745,0.1108 T0.768,0.1103 T0.7603,0.1088 T0.7518,0.1068 L0.7461,0.1068 Q0.7315,0.1068,0.7088,0.1103 T0.6805,0.1177 Q0.6756,0.1207,0.6699,0.1207 Q0.6667,0.1207,0.6545,0.1177 T0.631,0.1147 Q0.6269,0.1137,0.6225,0.1133 T0.616,0.1128 L0.6123,0.1128 T0.6103,0.1133 L0.6083,0.1157 T0.6034,0.1197 Q0.5961,0.1246,0.5921,0.1246 Q0.5904,0.1246,0.5835,0.1231 T0.5693,0.1217 L0.5661,0.1217 Q0.558,0.1217,0.5535,0.1231 T0.5446,0.1266 T0.5345,0.1296 Q0.5126,0.1316,0.4882,0.1316 T0.438,0.1405 Q0.4298,0.1434,0.425,0.1434 Q0.4209,0.1434,0.4173,0.1419 T0.4112,0.1405 T0.4027,0.1419 T0.3869,0.1434 Q0.3682,0.1434,0.3512,0.1494 Q0.3398,0.1533,0.3333,0.1533 Q0.3285,0.1533,0.3228,0.1513 L0.3212,0.1513 Q0.3179,0.1513,0.3155,0.1538 T0.3131,0.1592 Q0.3131,0.1612,0.3147,0.1632 Q0.3171,0.1652,0.3232,0.1667 T0.3406,0.1691 T0.3544,0.1701 L0.3601,0.1701 L0.3678,0.1701 L0.3771,0.1701 Q0.3909,0.1701,0.4031,0.1731 Q0.4177,0.178,0.4558,0.178 Q0.4793,0.178,0.4882,0.1761 L0.4915,0.1761 Q0.498,0.1761,0.5061,0.179 T0.5158,0.183 Q0.5166,0.183,0.5231,0.1835 T0.5341,0.1845 T0.545,0.1855 T0.5572,0.1874 T0.5661,0.1909 Q0.5677,0.1919,0.5702,0.1919 T0.5791,0.1894 T0.588,0.1869 Q0.5921,0.1869,0.5945,0.1899 Q0.5977,0.1919,0.6123,0.1919 Q0.6334,0.1919,0.6448,0.1879 Q0.6488,0.186,0.6537,0.186 Q0.6626,0.186,0.6784,0.1909 T0.6983,0.1958 Q0.704,0.1968,0.7206,0.1973 T0.7506,0.1993 T0.7689,0.2018 L0.7705,0.2018 L0.7741,0.2018 L0.7786,0.2018 Q0.8248,0.2018,0.8475,0.2136 Q0.8597,0.2196,0.8597,0.2255 T0.8483,0.2359 T0.8281,0.2404 Q0.8208,0.2404,0.7534,0.2493 Q0.7502,0.2502,0.7425,0.2512 T0.7287,0.2532 T0.7178,0.2542 L0.7153,0.2542 L0.7137,0.2542 Q0.7064,0.2542,0.6906,0.2591 T0.6715,0.2681 T0.6626,0.272 Q0.6594,0.272,0.6541,0.2705 T0.6464,0.269 T0.6431,0.27 Q0.6318,0.273,0.6034,0.276 Q0.6018,0.276,0.5998,0.2774 T0.5957,0.2799 T0.5904,0.2809 L0.5856,0.2809 Q0.5823,0.2799,0.575,0.2799 Q0.541,0.2799,0.5239,0.2868 Q0.5134,0.2908,0.5028,0.2908 Q0.4996,0.2908,0.4935,0.2903 T0.4842,0.2898 Q0.4704,0.2898,0.4635,0.2918 T0.4534,0.2997 L0.4534,0.3007 Q0.4534,0.3037,0.459,0.3046 T0.4753,0.3066 T0.4899,0.3076 Q0.4907,0.3076,0.5166,0.3106 T0.5507,0.3155 Q0.5921,0.3264,0.605,0.3264 Q0.6107,0.3264,0.6131,0.3254 Q0.6212,0.3225,0.6294,0.3225 Q0.6407,0.3225,0.6513,0.3274 Q0.6529,0.3294,0.6569,0.3294 Q0.6594,0.3294,0.665,0.3284 T0.6748,0.3274 T0.6821,0.3284 Q0.6861,0.3294,0.6967,0.3299 T0.7165,0.3314 T0.7299,0.3343 Q0.7324,0.3363,0.7486,0.3383 T0.7697,0.3422 Q0.7713,0.3432,0.7774,0.3452 T0.7887,0.3492 T0.8005,0.3546 T0.8127,0.3625 T0.8208,0.3719 Q0.8256,0.3798,0.8256,0.3848 Q0.8256,0.3877,0.8236,0.3902 T0.8171,0.3976 T0.809,0.4075 T0.8021,0.4189 T0.7968,0.4273 T0.7867,0.4322 T0.7616,0.4382 Q0.7543,0.4392,0.7437,0.4392 L0.7364,0.4392 L0.7299,0.4392 Q0.7202,0.4392,0.7161,0.4402 Q0.7072,0.4431,0.691,0.4431 L0.6845,0.4431 L0.6788,0.4431 Q0.6707,0.4431,0.6545,0.4461 T0.6334,0.452 Q0.6399,0.456,0.6626,0.457 Q0.6878,0.458,0.7024,0.4639 Q0.7064,0.4649,0.7186,0.4649 L0.7295,0.4649 L0.7413,0.4649 Q0.7591,0.4649,0.7697,0.4669 Q0.7818,0.4688,0.7818,0.4728 Q0.7818,0.4748,0.7798,0.4763 T0.7753,0.4787 L0.7737,0.4797 L0.7729,0.4797 Q0.7494,0.4827,0.7388,0.4827 Q0.7332,0.4827,0.7307,0.4817 L0.7291,0.4817 Q0.7226,0.4817,0.6878,0.4896 Q0.6829,0.4906,0.6772,0.4911 T0.6618,0.4921 T0.646,0.4931 T0.6342,0.4936 T0.6212,0.4931 T0.6115,0.4926 Q0.6083,0.4926,0.6058,0.4931 T0.5969,0.4955 T0.5819,0.499 T0.5629,0.5005 Q0.5572,0.5005,0.5527,0.501 T0.545,0.502 T0.5397,0.503 T0.5361,0.5045 T0.5337,0.5064 T0.5328,0.5094 L0.532,0.5094 Q0.532,0.5104,0.5337,0.5109 T0.5381,0.5114 T0.5438,0.5119 T0.5515,0.5124 L0.5604,0.5124 Q0.5661,0.5134,0.5746,0.5153 T0.5912,0.5173 L0.5977,0.5173 L0.6026,0.5173 Q0.6139,0.5173,0.6273,0.5218 T0.6407,0.5272 Q0.6448,0.5282,0.6683,0.5321 T0.6991,0.5381 Q0.7137,0.543,0.7664,0.548 Q0.7908,0.55,0.7908,0.5559 Q0.7908,0.5589,0.7859,0.5628 Q0.781,0.5658,0.7713,0.5658 Q0.7689,0.5658,0.7628,0.5653 T0.7543,0.5648 T0.7502,0.5658 Q0.7364,0.5678,0.6878,0.5678 Q0.674,0.5678,0.6699,0.5668 L0.6683,0.5668 Q0.6659,0.5668,0.6606,0.5678 T0.6513,0.5687 Q0.6464,0.5687,0.6391,0.5678 Q0.6334,0.5668,0.6302,0.5668 T0.6241,0.5687 T0.6164,0.5717 Q0.6123,0.5727,0.6099,0.5727 L0.6062,0.5727 T0.6022,0.5732 T0.5953,0.5737 Q0.5904,0.5747,0.5839,0.5747 T0.5726,0.5752 T0.5629,0.5776 T0.5458,0.5796 Q0.5418,0.5796,0.5324,0.5791 T0.5191,0.5786 Q0.5077,0.5786,0.5045,0.5806 Q0.498,0.5836,0.4899,0.5836 Q0.4858,0.5836,0.4777,0.5826 T0.4655,0.5816 L0.4631,0.5816 Q0.4582,0.5816,0.4436,0.5841 T0.4144,0.5865 L0.4051,0.5865 L0.3986,0.5865 T0.3933,0.587 T0.3897,0.5875 T0.3869,0.5885 T0.3844,0.5895 T0.3812,0.591 T0.3779,0.5925 Q0.3739,0.5955,0.3633,0.5955 L0.3585,0.5955 L0.3536,0.5955 Q0.3277,0.5955,0.3066,0.6053 Q0.3017,0.6083,0.296,0.6083 Q0.2912,0.6083,0.2839,0.6068 T0.2741,0.6053 Q0.2693,0.6053,0.2547,0.6048 T0.236,0.6044 Q0.2222,0.6044,0.193,0.6103 L0.1882,0.6103 Q0.1825,0.6103,0.1703,0.6083 T0.1525,0.6063 L0.15,0.6063 Q0.1436,0.6063,0.135,0.6073 T0.1168,0.6098 T0.1038,0.6113 Q0.0973,0.6123,0.0787,0.6123 L0.06,0.6123 L0.0414,0.6123 L0.0235,0.6123 Q0.0049,0.6133,0.0049,0.6172 L0.0057,0.6222 Q0.0073,0.6261,0.043,0.6261 L0.0454,0.6261 L0.0479,0.6261 Q0.0527,0.6261,0.0633,0.6281 T0.0803,0.6301 L0.0835,0.6301 L0.0916,0.6301 Q0.0998,0.6301,0.129,0.632 Q0.1768,0.636,0.206,0.64 Q0.2117,0.6409,0.2165,0.6409 Q0.2206,0.6409,0.2263,0.6405 T0.2336,0.64 L0.2384,0.64 L0.2409,0.64 T0.251,0.6395 T0.2644,0.639 Q0.2741,0.639,0.279,0.6409 Q0.283,0.6429,0.2972,0.6439 T0.3293,0.6459 T0.3528,0.6469 L0.3577,0.6469 Q0.3642,0.6469,0.3723,0.6449 T0.3844,0.6429 Q0.3901,0.6429,0.3933,0.6454 T0.4006,0.6479 Q0.4088,0.6479,0.4517,0.6558 Q0.4582,0.6568,0.4623,0.6568 Q0.4655,0.6568,0.4716,0.6563 T0.4826,0.6558 L0.4882,0.6558 Q0.5004,0.6558,0.5255,0.6607 Q0.5328,0.6627,0.5604,0.6647 T0.6152,0.6682 T0.644,0.6696 T0.6719,0.6721 T0.7056,0.6756 Q0.7113,0.6756,0.7198,0.6805 T0.738,0.6855 Q0.7453,0.6855,0.7551,0.6879 T0.7741,0.6939 T0.7912,0.7018 T0.8029,0.7102 Q0.8054,0.7132,0.8054,0.7151 Q0.8054,0.7191,0.8009,0.7216 T0.7908,0.7255 T0.779,0.7285 T0.7721,0.731 Q0.7672,0.7329,0.7632,0.7339 T0.7551,0.7354 T0.7486,0.7369 Q0.7478,0.7369,0.7445,0.7379 T0.7388,0.7394 T0.7324,0.7404 L0.7242,0.7413 T0.7161,0.7418 Q0.7105,0.7418,0.6955,0.7428 T0.6748,0.7438 L0.6699,0.7438 L0.6667,0.7438 Q0.6659,0.7438,0.6407,0.7468 Q0.6367,0.7478,0.6334,0.7478 T0.6245,0.7468 T0.6148,0.7458 L0.6099,0.7458 Q0.6018,0.7468,0.5864,0.7498 T0.5653,0.7532 T0.5596,0.7557 Q0.5596,0.7596,0.571,0.7616 Q0.5742,0.7626,0.5803,0.7631 T0.5929,0.7641 T0.6018,0.7656 L0.6087,0.7656 T0.6192,0.7666 T0.6277,0.7695 Q0.631,0.7705,0.6342,0.7705 Q0.6383,0.7705,0.6452,0.7685 T0.6537,0.7666 L0.6553,0.7666 Q0.6602,0.7666,0.6711,0.769 T0.6853,0.7715 Q0.691,0.7715,0.7048,0.775 T0.7242,0.7814 Q0.7324,0.7854,0.7445,0.7864 Q0.7478,0.7864,0.768,0.7873 T0.7972,0.7893 Q0.7989,0.7893,0.8017,0.7898 T0.8054,0.7903 L0.8082,0.7903 T0.811,0.7908 T0.8131,0.7913 T0.8151,0.7918 L0.8167,0.7928 T0.8179,0.7943 T0.8191,0.7957 T0.8204,0.7977 T0.8208,0.8002 Q0.8208,0.8032,0.8171,0.8051 T0.8074,0.8081 T0.7997,0.8091 Q0.7932,0.8121,0.7737,0.8121 Q0.7664,0.8121,0.7413,0.8111 L0.7364,0.8111 Q0.7275,0.8111,0.7214,0.8121 T0.7084,0.8155 T0.6991,0.819 Q0.6934,0.82,0.6723,0.8205 T0.6472,0.8239 Q0.6423,0.8269,0.6375,0.8269 Q0.6358,0.8269,0.6338,0.8264 T0.6294,0.8254 T0.6253,0.8249 Q0.6042,0.8249,0.5961,0.8289 Q0.5921,0.8318,0.5839,0.8318 Q0.5783,0.8318,0.5645,0.8299 L0.5604,0.8299 Q0.5531,0.8299,0.5337,0.8368 Q0.5296,0.8378,0.5255,0.8378 Q0.5239,0.8378,0.5195,0.8373 T0.5118,0.8368 Q0.5061,0.8368,0.4996,0.8388 Q0.4947,0.8388,0.4882,0.8398 Q0.4777,0.8417,0.4753,0.8427 T0.4728,0.8467 Q0.4728,0.8487,0.4769,0.8492 T0.4886,0.8501 T0.5004,0.8516 Q0.5036,0.8516,0.515,0.8521 T0.5345,0.8546 Q0.5426,0.8556,0.5596,0.8556 L0.5649,0.8556 L0.5702,0.8556 L0.5791,0.8556 Q0.5921,0.8566,0.6135,0.8571 T0.6383,0.8586 Q0.6683,0.8615,0.6764,0.8615 L0.6776,0.8615 L0.6788,0.8615 Q0.7032,0.8615,0.7032,0.8684 Q0.7032,0.8714,0.6995,0.8749 T0.6959,0.8803 L0.6959,0.8813 Q0.6991,0.8843,0.7153,0.8843 Q0.7218,0.8843,0.7259,0.8833 L0.7299,0.8833 Q0.7324,0.8833,0.7348,0.8838 T0.7393,0.8848 T0.7433,0.8863 L0.7474,0.8882 T0.751,0.8892 Q0.7616,0.8922,0.7948,0.8952 Q0.7981,0.8952,0.8082,0.8981 T0.8297,0.9011 T0.8528,0.9026 T0.8747,0.907 T0.8856,0.9149 L0.8856,0.9159 Q0.8856,0.9179,0.8848,0.9189 T0.8828,0.9209 T0.88,0.9228 T0.8767,0.9243 T0.8731,0.9248 T0.8698,0.9253 T0.8666,0.9258 L0.8646,0.9258 Q0.8621,0.9258,0.8577,0.9263 T0.85,0.9268 T0.8439,0.9273 T0.8402,0.9278 Q0.8386,0.9298,0.8358,0.9308 T0.8305,0.9322 T0.8244,0.9332 T0.8183,0.9337 Q0.8135,0.9347,0.8025,0.9372 T0.7859,0.9416 Q0.7778,0.9436,0.7717,0.9471 T0.7624,0.9515 Q0.7575,0.9535,0.7486,0.9535 Q0.7461,0.9535,0.7397,0.953 T0.7291,0.9525 Q0.7234,0.9525,0.7186,0.953 T0.7137,0.957 T0.7194,0.9614 Q0.7567,0.9634,0.7664,0.9654 Q0.7745,0.9674,0.7762,0.9674 L0.7908,0.9674 Q0.7924,0.9664,0.7948,0.9664 Q0.8029,0.9664,0.8082,0.9679 T0.8224,0.9723 T0.8362,0.9773 Q0.8483,0.9812,0.871,0.9812 L0.8751,0.9812 Q0.8873,0.9812,0.8929,0.9822 T0.9165,0.9876 T0.9408,0.9931 Q0.9513,0.996,0.9935,0.996 Z M0.9968,0.998 L0.9976,0.003 Q0.9838,0.002,0.9708,0.0059 Q0.9659,0.0069,0.9327,0.0059 T0.8881,0.0099 Q0.8767,0.0138,0.8658,0.0163 T0.8491,0.0218 Q0.8418,0.0247,0.8341,0.0247 T0.8232,0.0257 Q0.8191,0.0277,0.7997,0.0292 T0.7737,0.0326 Q0.7697,0.0336,0.7672,0.0336 T0.7612,0.0321 T0.7543,0.0307 T0.747,0.0317 Q0.7397,0.0326,0.7336,0.0356 T0.717,0.0406 Q0.6918,0.0445,0.6861,0.0475 Q0.6845,0.0485,0.6772,0.0485 T0.6638,0.05 T0.6577,0.0549 T0.6642,0.0598 T0.6796,0.0613 T0.6902,0.0623 Q0.691,0.0623,0.6946,0.0658 T0.7064,0.0702 L0.7161,0.0702 Q0.7194,0.0702,0.7242,0.0697 T0.7332,0.0692 Q0.7413,0.0692,0.7579,0.0717 T0.781,0.0762 Q0.7867,0.0781,0.8171,0.0786 T0.85,0.0801 L0.8532,0.0801 Q0.8548,0.0801,0.8613,0.0796 T0.8727,0.0791 Q0.8832,0.0791,0.8913,0.0811 Q0.897,0.0831,0.897,0.0851 Q0.897,0.088,0.8873,0.0905 T0.8735,0.093 Q0.871,0.093,0.8447,0.0984 T0.8143,0.1039 Q0.7981,0.1039,0.781,0.1078 Q0.7778,0.1088,0.7745,0.1088 T0.7644,0.1073 T0.7518,0.1048 L0.7453,0.1048 Q0.7299,0.1048,0.7076,0.1083 T0.6788,0.1157 Q0.6748,0.1187,0.6699,0.1187 Q0.6675,0.1187,0.6557,0.1157 T0.6318,0.1118 Q0.6164,0.1108,0.6135,0.1108 T0.6095,0.1113 T0.6067,0.1142 T0.6018,0.1187 Q0.5953,0.1227,0.5921,0.1227 Q0.5904,0.1227,0.5839,0.1212 T0.5693,0.1187 L0.5661,0.1187 Q0.558,0.1187,0.5527,0.1207 T0.5434,0.1246 T0.5337,0.1266 Q0.5126,0.1296,0.4882,0.1296 T0.4371,0.1385 Q0.4298,0.1414,0.425,0.1414 Q0.4225,0.1414,0.4189,0.1395 T0.4112,0.1375 Q0.4079,0.1375,0.4019,0.1395 T0.3869,0.1414 Q0.3682,0.1414,0.3504,0.1474 Q0.3398,0.1513,0.3333,0.1513 Q0.3293,0.1513,0.3228,0.1494 L0.3204,0.1494 Q0.3179,0.1494,0.3155,0.1508 T0.3118,0.1543 T0.3106,0.1592 T0.3127,0.1642 T0.32,0.1677 T0.3305,0.1701 T0.3435,0.1716 T0.3544,0.1721 Q0.3569,0.1731,0.3601,0.1731 Q0.3625,0.1731,0.3686,0.1726 T0.3779,0.1721 Q0.3901,0.1721,0.4023,0.1751 Q0.4177,0.18,0.455,0.18 Q0.4793,0.18,0.4882,0.178 L0.4915,0.178 Q0.4964,0.178,0.5045,0.1815 T0.5158,0.185 Q0.5564,0.1889,0.5645,0.1929 Q0.5677,0.1939,0.571,0.1939 Q0.575,0.1939,0.5807,0.1919 T0.5888,0.1899 T0.5929,0.1909 Q0.5969,0.1949,0.6123,0.1949 Q0.6334,0.1949,0.6456,0.1899 Q0.6488,0.1879,0.6537,0.1879 Q0.661,0.1879,0.6772,0.1929 T0.6983,0.1978 Q0.704,0.1988,0.7206,0.1998 T0.7502,0.2018 T0.7664,0.2038 Q0.7672,0.2038,0.7818,0.2043 T0.8151,0.2067 T0.8459,0.2156 Q0.8573,0.2206,0.8573,0.2255 Q0.8573,0.2295,0.8516,0.2324 T0.8394,0.2369 T0.8281,0.2384 Q0.8208,0.2384,0.7526,0.2473 Q0.7494,0.2483,0.7421,0.2493 T0.7287,0.2512 T0.7178,0.2522 L0.7153,0.2522 L0.7137,0.2522 Q0.7056,0.2522,0.6898,0.2572 T0.6691,0.2671 Q0.6667,0.269,0.6634,0.269 Q0.661,0.269,0.6557,0.2681 T0.6472,0.2671 Q0.6448,0.2671,0.6415,0.2681 Q0.631,0.271,0.6034,0.274 Q0.5994,0.274,0.5961,0.2765 T0.5904,0.2789 L0.5864,0.2789 Q0.5831,0.2779,0.5742,0.2779 Q0.541,0.2779,0.5223,0.2849 Q0.5126,0.2888,0.5028,0.2888 Q0.5004,0.2888,0.4943,0.2883 T0.4842,0.2878 Q0.4704,0.2878,0.4627,0.2898 T0.4509,0.2987 Q0.4501,0.2997,0.4501,0.3007 Q0.4501,0.3046,0.4574,0.3066 T0.4765,0.3091 T0.4899,0.3096 Q0.4931,0.3106,0.5061,0.3121 T0.5316,0.315 T0.5499,0.3175 Q0.5507,0.3175,0.5572,0.3195 T0.5685,0.3225 T0.5803,0.3254 T0.5933,0.3279 T0.605,0.3284 T0.6148,0.3274 Q0.6221,0.3244,0.6294,0.3244 Q0.6399,0.3244,0.6496,0.3294 Q0.6529,0.3314,0.6577,0.3314 Q0.6602,0.3314,0.6663,0.3304 T0.6756,0.3294 T0.6813,0.3304 Q0.6837,0.3304,0.6873,0.3309 L0.6946,0.3318 T0.7024,0.3323 T0.7105,0.3328 T0.7178,0.3338 T0.7238,0.3348 T0.7283,0.3363 Q0.7324,0.3383,0.7482,0.3403 T0.7689,0.3442 Q0.7697,0.3442,0.779,0.3477 T0.794,0.3536 T0.8074,0.3615 T0.8183,0.3729 Q0.8232,0.3808,0.8232,0.3848 Q0.8232,0.3867,0.8216,0.3892 T0.8151,0.3961 T0.8062,0.406 T0.7997,0.4179 T0.7952,0.4263 T0.7855,0.4308 T0.7616,0.4362 Q0.7543,0.4372,0.7445,0.4372 L0.7372,0.4372 L0.7307,0.4372 Q0.7202,0.4372,0.7153,0.4382 Q0.7064,0.4402,0.691,0.4402 L0.6845,0.4402 L0.6788,0.4402 Q0.6699,0.4402,0.6533,0.4436 T0.6318,0.451 Q0.6302,0.451,0.6302,0.452 Q0.6302,0.457,0.6626,0.459 Q0.6869,0.4609,0.7015,0.4659 Q0.7064,0.4669,0.7202,0.4669 L0.7311,0.4669 L0.7429,0.4669 Q0.7599,0.4669,0.7689,0.4688 Q0.7794,0.4708,0.7794,0.4738 L0.7786,0.4748 T0.777,0.4763 T0.7749,0.4773 L0.7737,0.4777 L0.7729,0.4777 Q0.7502,0.4797,0.738,0.4797 L0.7315,0.4797 L0.7291,0.4797 Q0.7226,0.4797,0.6869,0.4876 Q0.6821,0.4886,0.6768,0.4891 T0.6614,0.4901 T0.6456,0.4916 L0.6342,0.4916 Q0.6294,0.4916,0.6217,0.4911 T0.6115,0.4906 Q0.6083,0.4906,0.6054,0.4911 T0.5961,0.4936 T0.5815,0.4965 T0.5629,0.4985 Q0.5507,0.4985,0.5442,0.4995 T0.5345,0.5025 T0.5304,0.5084 L0.5296,0.5094 Q0.5296,0.5114,0.5316,0.5124 T0.5373,0.5138 T0.5442,0.5143 L0.5523,0.5143 L0.5604,0.5143 Q0.5637,0.5153,0.5677,0.5158 T0.5742,0.5173 T0.5811,0.5188 T0.5904,0.5193 L0.5977,0.5193 L0.6026,0.5193 Q0.6107,0.5193,0.6168,0.5208 T0.6294,0.5252 T0.6399,0.5292 Q0.6448,0.5302,0.6679,0.5341 T0.6983,0.541 Q0.7129,0.545,0.7664,0.55 Q0.7883,0.5519,0.7883,0.5559 Q0.7883,0.5579,0.7843,0.5608 T0.7721,0.5638 Q0.7697,0.5638,0.764,0.5633 T0.7559,0.5628 L0.7502,0.5628 Q0.7364,0.5648,0.6869,0.5648 L0.6699,0.5648 L0.6675,0.5648 Q0.665,0.5648,0.6602,0.5658 T0.6513,0.5668 Q0.6464,0.5668,0.6399,0.5658 Q0.6342,0.5648,0.6302,0.5648 T0.6225,0.5668 T0.6156,0.5697 Q0.6107,0.5707,0.6087,0.5707 T0.6034,0.5712 T0.5953,0.5717 Q0.5904,0.5727,0.5835,0.5727 T0.5718,0.5732 T0.562,0.5757 Q0.558,0.5767,0.5483,0.5767 L0.5349,0.5767 L0.5207,0.5767 Q0.5069,0.5767,0.5028,0.5786 Q0.4972,0.5816,0.4899,0.5816 Q0.4858,0.5816,0.4781,0.5806 T0.4663,0.5796 L0.4631,0.5796 Q0.4582,0.5796,0.4432,0.5821 T0.4144,0.5846 L0.4071,0.5846 L0.4011,0.5846 T0.3958,0.5851 T0.3921,0.5856 T0.3889,0.5861 T0.3865,0.5865 T0.384,0.5875 L0.382,0.5885 L0.3796,0.5895 L0.3771,0.5905 Q0.3731,0.5925,0.365,0.5925 L0.3601,0.5925 L0.3552,0.5925 Q0.3277,0.5925,0.3049,0.6044 Q0.3017,0.6053,0.296,0.6053 Q0.292,0.6053,0.2847,0.6044 T0.2741,0.6034 Q0.2693,0.6034,0.2547,0.6029 T0.236,0.6024 Q0.2222,0.6024,0.1922,0.6073 Q0.1906,0.6083,0.1882,0.6083 Q0.1833,0.6083,0.1711,0.6063 T0.1533,0.6044 Q0.1517,0.6034,0.1492,0.6034 Q0.1436,0.6034,0.135,0.6048 T0.1168,0.6078 T0.103,0.6093 Q0.0973,0.6103,0.0787,0.6103 L0.0604,0.6103 L0.0414,0.6103 L0.0235,0.6103 Q0.0024,0.6113,0.0024,0.6172 Q0.0024,0.6192,0.0032,0.6231 Q0.0049,0.6281,0.0333,0.6281 L0.0414,0.6281 L0.0479,0.6281 Q0.0519,0.6281,0.0624,0.6301 T0.0803,0.632 L0.0835,0.632 L0.0916,0.632 Q0.0989,0.632,0.1281,0.634 L0.206,0.6419 Q0.2117,0.6429,0.2174,0.6429 Q0.2214,0.6429,0.2271,0.6424 T0.2344,0.6419 L0.2376,0.6419 Q0.2393,0.6429,0.2417,0.6429 T0.2526,0.6419 T0.2652,0.6409 Q0.2741,0.6409,0.2782,0.6429 T0.2968,0.6459 T0.3293,0.6479 T0.352,0.6489 Q0.3552,0.6499,0.3585,0.6499 Q0.365,0.6499,0.3731,0.6474 T0.3844,0.6449 Q0.3885,0.6449,0.3917,0.6474 T0.4006,0.6499 Q0.4088,0.6499,0.4509,0.6578 Q0.4574,0.6588,0.4631,0.6588 Q0.4655,0.6588,0.4716,0.6583 T0.4834,0.6578 L0.4874,0.6578 Q0.5004,0.6588,0.5255,0.6637 Q0.532,0.6647,0.56,0.6667 T0.6148,0.6701 T0.644,0.6716 Q0.6464,0.6726,0.6594,0.6736 T0.6861,0.6756 T0.7048,0.6775 Q0.7097,0.6775,0.7186,0.6825 T0.738,0.6874 Q0.7518,0.6874,0.7729,0.6958 T0.8005,0.7122 Q0.8029,0.7141,0.8029,0.7151 Q0.8029,0.7191,0.7968,0.7216 T0.7818,0.726 T0.7705,0.729 L0.764,0.731 T0.7583,0.7324 T0.753,0.7334 T0.7486,0.7349 Q0.7251,0.7399,0.7161,0.7399 Q0.7097,0.7399,0.6951,0.7409 T0.6748,0.7418 L0.6703,0.7418 L0.6667,0.7418 Q0.6659,0.7418,0.6399,0.7448 L0.6334,0.7448 Q0.631,0.7448,0.6249,0.7443 T0.6148,0.7438 L0.6099,0.7438 Q0.601,0.7448,0.5856,0.7473 T0.5645,0.7507 Q0.5572,0.7517,0.5572,0.7547 T0.5616,0.7606 T0.5702,0.7646 Q0.5734,0.7646,0.5779,0.7651 T0.5864,0.7661 T0.5949,0.7671 T0.6018,0.7676 L0.6071,0.7676 T0.6135,0.7681 T0.62,0.769 T0.6269,0.771 T0.6342,0.7725 Q0.6391,0.7725,0.6464,0.7705 T0.6541,0.7685 L0.6553,0.7685 Q0.6586,0.7685,0.6699,0.771 T0.6853,0.7735 Q0.6902,0.7735,0.704,0.777 T0.7226,0.7834 Q0.7315,0.7873,0.7445,0.7883 Q0.747,0.7883,0.7676,0.7893 T0.7972,0.7913 Q0.7989,0.7913,0.8017,0.7918 T0.8058,0.7923 T0.809,0.7928 T0.8114,0.7933 T0.8131,0.7938 T0.8147,0.7943 T0.8159,0.7953 L0.8171,0.7967 T0.8175,0.7982 Q0.8183,0.7992,0.8183,0.8002 Q0.8183,0.8022,0.8155,0.8032 T0.807,0.8051 T0.7989,0.8071 Q0.7932,0.8091,0.7737,0.8091 L0.7413,0.8091 L0.7372,0.8091 Q0.7275,0.8091,0.721,0.8101 T0.7072,0.8136 T0.6983,0.817 Q0.6942,0.818,0.6825,0.818 T0.6602,0.819 T0.6456,0.822 Q0.6415,0.8249,0.6375,0.8249 Q0.6367,0.8249,0.6326,0.8239 T0.6253,0.8229 Q0.6034,0.8229,0.5953,0.8279 Q0.5912,0.8289,0.5848,0.8289 Q0.5775,0.8289,0.5645,0.8279 Q0.5629,0.8269,0.5604,0.8269 Q0.5523,0.8269,0.5328,0.8348 Q0.5296,0.8358,0.5264,0.8358 Q0.5247,0.8358,0.5203,0.8353 T0.5126,0.8348 Q0.5061,0.8348,0.4988,0.8358 Q0.4947,0.8368,0.4882,0.8378 Q0.4826,0.8388,0.4797,0.8388 T0.474,0.8398 T0.4704,0.8422 T0.4696,0.8462 T0.472,0.8501 T0.4781,0.8521 T0.4854,0.8526 L0.4935,0.8526 T0.4996,0.8536 Q0.5036,0.8536,0.515,0.8546 T0.5337,0.8566 Q0.5426,0.8576,0.5596,0.8576 L0.5657,0.8576 L0.571,0.8576 L0.5791,0.8576 Q0.5921,0.8586,0.6135,0.8591 T0.6383,0.8605 Q0.6683,0.8635,0.6764,0.8635 Q0.6999,0.8635,0.6999,0.8684 Q0.6999,0.8694,0.6967,0.8734 T0.6934,0.8803 L0.6934,0.8823 Q0.6951,0.8863,0.7137,0.8863 Q0.7218,0.8863,0.7267,0.8853 L0.7299,0.8853 Q0.734,0.8853,0.7409,0.8882 T0.7502,0.8912 Q0.7607,0.8942,0.794,0.8971 Q0.7972,0.8971,0.8078,0.9001 T0.8297,0.9031 Q0.8475,0.9031,0.8646,0.9065 T0.8824,0.9149 L0.8824,0.9159 Q0.8824,0.9169,0.882,0.9179 T0.8808,0.9194 L0.8792,0.9204 T0.8767,0.9214 T0.8743,0.9224 T0.8715,0.9228 L0.8686,0.9228 T0.8662,0.9233 T0.8637,0.9238 L0.8556,0.9238 T0.8447,0.9243 T0.8386,0.9268 Q0.837,0.9278,0.835,0.9288 T0.8305,0.9303 T0.8244,0.9308 T0.8175,0.9318 Q0.8127,0.9327,0.8017,0.9352 T0.7851,0.9397 Q0.777,0.9416,0.7705,0.9451 T0.7616,0.9496 Q0.7575,0.9505,0.7494,0.9505 L0.7405,0.9505 L0.7307,0.9505 Q0.7234,0.9505,0.7178,0.9515 Q0.7145,0.9515,0.7125,0.9535 T0.7105,0.9575 Q0.7105,0.9624,0.7194,0.9634 Q0.7567,0.9654,0.7664,0.9674 Q0.7745,0.9693,0.7762,0.9693 L0.7908,0.9693 L0.7948,0.9693 Q0.8005,0.9693,0.8058,0.9698 T0.8143,0.9718 T0.824,0.9753 T0.8354,0.9792 Q0.8483,0.9832,0.871,0.9832 L0.8739,0.9832 L0.8767,0.9832 Q0.8873,0.9832,0.8921,0.9842 Q0.8978,0.9852,0.9157,0.9896 T0.94,0.996 Q0.9424,0.996,0.9469,0.9965 T0.9566,0.997 T0.9676,0.9975 T0.9781,0.998 L0.9874,0.998 L0.9943,0.998 L0.9968,0.998 Z",type:0}},"\uE0CC":{type:5,data:{d:"M1,0.5071 L0.8623,0.7102 L0.5865,0.7102 L0.4489,0.5071 L0.5865,0.3045 L0.8623,0.3045 Z M0.4135,0.7974 L0.2758,1 L0,1 L0,0.5944 L0.2758,0.5944 Z M0.4135,0.2026 L0.2758,0.4056 L0,0.4056 L0,0 L0.2758,0 Z",type:0}},"\uE0CD":{type:5,data:{d:"M0.9726,0.5071 L0.8451,0.3184 L0.59,0.3184 L0.4624,0.5071 L0.59,0.6955 L0.8451,0.6955 Z M1,0.5071 L0.8588,0.716 L0.5768,0.716 L0.4355,0.5071 L0.5768,0.2982 L0.8588,0.2982 Z M0.401,0.7911 L0.2735,0.6028 L0.0236,0.6028 L0.0236,0.9799 L0.2735,0.9799 Z M0.4284,0.7911 L0.2872,1 L0,1 L0,0.5826 L0.2872,0.5826 Z M0.401,0.2089 L0.2735,0.0201 L0.0236,0.0201 L0.0236,0.3972 L0.2735,0.3972 Z M0.4284,0.2089 L0.2872,0.4174 L0,0.4174 L0,0 L0.2872,0 Z",type:0}},"\uE0CE":{type:5,data:{d:"M1,0.4996 Q1,0.5365,0.9924,0.568 T0.9718,0.6177 T0.9433,0.6363 L0.9425,0.6367 Q0.9355,0.6367,0.9285,0.6326 L0.9308,0.6326 Q0.9129,0.6195,0.9013,0.587 T0.8871,0.5164 T0.8943,0.4373 T0.9254,0.3687 L0.9254,0.3691 Q0.9339,0.3628,0.9425,0.3628 Q0.9584,0.3628,0.9716,0.3811 T0.9924,0.431 T1,0.4996 Z M0.9234,0.6321 L0.8776,0.7169 Q0.8791,0.732,0.8791,0.7441 Q0.8791,0.781,0.8716,0.8123 T0.8508,0.862 T0.8224,0.8809 L0.8216,0.8809 Q0.8154,0.8809,0.8092,0.8775 L0.8088,0.8775 Q0.7905,0.8633,0.7792,0.8297 T0.766,0.7571 T0.775,0.6768 T0.8088,0.6086 L0.7431,0.6065 Q0.719,0.6313,0.7072,0.6705 T0.6965,0.7487 T0.7097,0.823 T0.7423,0.8763 L0.7913,0.8775 L0.7314,0.9895 L0.4648,0.5038 L0.7299,0.0176 L0.7882,0.1229 L0.7404,0.1212 Q0.7244,0.138,0.7136,0.1617 T0.6982,0.2108 T0.6943,0.2632 T0.7003,0.3144 T0.7159,0.3586 T0.7396,0.3909 L0.8072,0.3926 Q0.7894,0.3796,0.7777,0.3479 T0.7635,0.2789 T0.7697,0.2011 T0.7987,0.1326 Q0.8092,0.1225,0.8204,0.1225 Q0.8321,0.1225,0.8426,0.1332 T0.8609,0.1623 T0.8731,0.2062 T0.8776,0.2592 Q0.8776,0.268,0.8768,0.2815 L0.9219,0.3628 L0.8644,0.3612 Q0.8403,0.3855,0.8284,0.4247 T0.8177,0.5029 T0.8309,0.5772 T0.8632,0.6305 Z M0.6759,0.6384 Q0.6576,0.625,0.6457,0.5914 T0.6319,0.5185 T0.6407,0.4375 T0.6751,0.3691 L0.609,0.367 Q0.5849,0.3918,0.5731,0.431 T0.5626,0.509 T0.5758,0.5833 T0.6082,0.6367 Z M0.6459,0.0025 L0.391,0.4551 L0.0035,0.4551 L0.246,0 Z M0.6553,1 L0.2421,1 L0,0.5449 L0.3875,0.5449 Z",type:0}},"\uE0CF":{type:5,data:{d:"M0.4996,0 Q0.5562,0,0.5961,0.0166 T0.6364,0.0566 L0.6368,0.0575 Q0.6368,0.0646,0.6324,0.0713 L0.6324,0.0692 Q0.6196,0.0868,0.5872,0.0986 T0.5166,0.1128 T0.4373,0.1057 T0.3689,0.0747 L0.3694,0.0747 Q0.3627,0.0663,0.3627,0.0575 Q0.3627,0.0336,0.4028,0.0168 T0.4996,0 Z M0.6324,0.0768 L0.717,0.1225 Q0.7321,0.1212,0.744,0.1212 Q0.8007,0.1212,0.8406,0.1378 T0.8809,0.1779 L0.8813,0.1783 Q0.8813,0.1846,0.8778,0.1909 Q0.8636,0.2093,0.8299,0.2208 T0.7573,0.2343 T0.6769,0.2253 T0.6089,0.1913 L0.6067,0.2567 Q0.6315,0.281,0.6707,0.2928 T0.7489,0.3035 T0.8231,0.2903 T0.8764,0.258 L0.8778,0.2085 L0.9898,0.2685 L0.504,0.5352 L0.0177,0.2701 L0.1227,0.2118 L0.1213,0.2596 Q0.1457,0.2836,0.1851,0.2955 T0.2635,0.3062 T0.3377,0.293 T0.3911,0.2605 L0.3928,0.193 Q0.38,0.2106,0.3483,0.2221 T0.2792,0.2364 T0.2013,0.2303 T0.1324,0.2013 Q0.1222,0.1909,0.1222,0.1795 Q0.1222,0.156,0.1623,0.1393 T0.2591,0.1225 Q0.2679,0.1225,0.2817,0.1233 L0.3627,0.078 L0.3609,0.1359 Q0.3857,0.1598,0.4249,0.1718 T0.5031,0.1825 T0.5773,0.1693 T0.6306,0.1367 Z M0.6386,0.3242 Q0.6253,0.3427,0.5917,0.3544 T0.5186,0.3683 T0.4376,0.3595 T0.3689,0.3251 L0.3671,0.3909 Q0.3915,0.4148,0.4309,0.4268 T0.5093,0.4375 T0.5835,0.4243 T0.6368,0.3918 Z M0.0027,0.354 L0.4553,0.6091 L0.4553,0.9962 L0,0.7542 Z M1,0.3448 L1,0.7576 L0.5447,1 L0.5447,0.6128 Z",type:0}},"\uE0D0":{type:5,data:{d:"M0,0.7699 Q0,0.7172,0.0277,0.6731 T0.103,0.6032 T0.2066,0.5774 Q0.2487,0.5774,0.2865,0.5922 T0.3526,0.6339 L0.3935,0.6715 Q0.4218,0.6984,0.438,0.7336 T0.4541,0.8075 Q0.4541,0.8602,0.4264,0.9046 T0.3511,0.9745 T0.2475,1 Q0.2054,1,0.1676,0.9852 T0.1016,0.9435 L0.0606,0.9059 Q0.0317,0.879,0.0159,0.8438 T0,0.7699 Z M0.5459,0.7699 Q0.5459,0.7172,0.5736,0.6731 T0.6489,0.6032 T0.7525,0.5774 Q0.7946,0.5774,0.8324,0.5922 T0.8984,0.6339 L0.9394,0.6715 Q0.9579,0.6892,0.9714,0.7105 T0.9925,0.7567 T1,0.8075 Q1,0.8602,0.9723,0.9046 T0.897,0.9745 T0.7934,1 Q0.7513,1,0.7135,0.9852 T0.6474,0.9435 L0.6065,0.9059 Q0.5776,0.879,0.5617,0.8438 T0.5459,0.7699 Z M0,0.1925 Q0,0.1398,0.0277,0.0957 T0.103,0.0258 T0.2066,0 Q0.2487,0,0.2865,0.0148 T0.3526,0.0565 L0.3935,0.0941 Q0.4218,0.121,0.438,0.1562 T0.4541,0.2301 Q0.4541,0.2828,0.4264,0.3269 T0.3511,0.3968 T0.2475,0.4226 Q0.2054,0.4226,0.1676,0.4078 T0.1016,0.3661 L0.0606,0.3285 Q0.0317,0.3016,0.0159,0.2664 T0,0.1925 Z M0.5459,0.1925 Q0.5459,0.1398,0.5736,0.0957 T0.6489,0.0258 T0.7525,0 Q0.7946,0,0.8324,0.0148 T0.8984,0.0565 L0.9394,0.0941 Q0.9677,0.121,0.9838,0.1562 T1,0.2301 Q1,0.2828,0.9723,0.3269 T0.897,0.3968 T0.7934,0.4226 Q0.7513,0.4226,0.7135,0.4078 T0.6474,0.3661 L0.6065,0.3285 Q0.5874,0.3108,0.5741,0.2895 T0.5534,0.2433 T0.5459,0.1925 Z M0.3301,0.6403 Q0.3306,0.6403,0.3312,0.6409 L0.3272,0.6371 L0.3272,0.6371 Z M0.8759,0.6403 Q0.8765,0.6403,0.8771,0.6409 Q0.8748,0.6387,0.8725,0.6371 L0.8731,0.6371 Z M0.3301,0.0629 Q0.3306,0.0629,0.3312,0.0634 L0.3272,0.0597 L0.3272,0.0602 Z M0.8759,0.0629 Q0.8765,0.0629,0.8771,0.0634 Q0.8748,0.0613,0.8725,0.0597 Q0.8731,0.0597,0.8731,0.0602 Z M0.779,0.4113 L0.7501,0.3849 Q0.7046,0.3844,0.6636,0.3661 Q0.7132,0.407,0.779,0.4113 Z M0.7957,0.4118 Q0.8477,0.4113,0.8918,0.3874 T0.9619,0.3223 T0.9885,0.2323 L0.9585,0.2048 Q0.9538,0.2769,0.8987,0.3282 T0.7657,0.3844 Z M0.9879,0.2167 Q0.9827,0.1554,0.9388,0.1097 Q0.9585,0.1478,0.959,0.1898 Z M0.2331,0.4113 L0.2043,0.3849 Q0.1587,0.3844,0.1177,0.3661 Q0.1673,0.407,0.2331,0.4113 Z M0.2499,0.4118 Q0.2885,0.4118,0.324,0.3973 T0.3852,0.3589 T0.4264,0.3019 T0.4426,0.2323 L0.4126,0.2048 Q0.408,0.2769,0.3529,0.3282 T0.2198,0.3844 Z M0.442,0.2167 Q0.4368,0.1554,0.393,0.1097 Q0.4126,0.1478,0.4132,0.1903 Z M0.779,0.9887 L0.7501,0.9624 Q0.7046,0.9618,0.6636,0.9435 Q0.7132,0.9844,0.779,0.9887 Z M0.7957,0.9892 Q0.8477,0.9887,0.8918,0.9648 T0.9619,0.8997 T0.9885,0.8097 L0.9585,0.7823 Q0.9538,0.8543,0.8987,0.9056 T0.7657,0.9618 Z M0.9879,0.7941 Q0.9827,0.7328,0.9388,0.6871 Q0.9585,0.7253,0.959,0.7672 Z M0.2331,0.9887 L0.2043,0.9624 Q0.1587,0.9618,0.1177,0.9435 Q0.1673,0.9844,0.2331,0.9887 Z M0.2499,0.9892 Q0.3018,0.9887,0.3459,0.9648 T0.416,0.8997 T0.4426,0.8102 L0.4126,0.7823 Q0.408,0.8543,0.3529,0.9056 T0.2198,0.9618 Z M0.442,0.7941 Q0.4368,0.7328,0.393,0.6871 Q0.4126,0.7253,0.4132,0.7672 Z M0.3191,0.6452 Q0.2943,0.622,0.2643,0.6091 T0.2066,0.5962 Q0.1795,0.5962,0.1497,0.6091 T0.0949,0.6441 T0.0537,0.6995 T0.0375,0.7699 Q0.0375,0.8419,0.0941,0.8941 Q0.1189,0.9172,0.1489,0.9304 T0.2066,0.9435 Q0.2337,0.9435,0.2634,0.9304 T0.3182,0.8952 T0.3595,0.8398 T0.3756,0.7699 Q0.3756,0.6978,0.3191,0.6452 Z M0.026,0.7731 L0.026,0.7699 Q0.026,0.6935,0.0854,0.6376 Q0.0658,0.6538,0.0514,0.6739 T0.0289,0.718 T0.0202,0.7677 Z M0.0271,0.7892 L0.0208,0.7833 Q0.0254,0.8419,0.0681,0.886 Q0.0664,0.8828,0.0646,0.879 Q0.0329,0.8382,0.0271,0.7892 Z M0.3866,0.7823 Q0.382,0.8511,0.3278,0.9016 Q0.3843,0.8565,0.3918,0.7871 Z M0.3872,0.7677 L0.393,0.7726 L0.393,0.7699 Q0.393,0.7349,0.3791,0.7038 Q0.3739,0.6973,0.3681,0.6914 Q0.3866,0.7274,0.3872,0.7677 Z M0.865,0.6452 Q0.8402,0.622,0.8102,0.6091 T0.7525,0.5962 Q0.7305,0.5962,0.7072,0.6043 T0.6619,0.628 T0.6223,0.6642 T0.5941,0.7124 T0.5834,0.7699 Q0.5834,0.8419,0.6399,0.8941 Q0.6561,0.9097,0.6757,0.9207 T0.7149,0.9376 T0.7525,0.9435 Q0.7796,0.9435,0.8093,0.9304 T0.8641,0.8952 T0.9054,0.8398 T0.9215,0.7699 Q0.9215,0.6978,0.865,0.6452 Z M0.5718,0.7731 L0.5718,0.7699 Q0.5718,0.6935,0.6313,0.6376 Q0.6013,0.6618,0.584,0.6954 T0.5661,0.7677 Z M0.573,0.7892 L0.5666,0.7833 Q0.5713,0.8419,0.614,0.886 Q0.6122,0.8828,0.6105,0.879 Q0.5788,0.8382,0.573,0.7892 Z M0.9325,0.7823 Q0.9279,0.8511,0.8736,0.9016 Q0.9308,0.8565,0.9377,0.7871 Z M0.9331,0.7672 L0.9388,0.7726 L0.9388,0.7699 Q0.9388,0.7349,0.925,0.7038 Q0.9198,0.6973,0.914,0.6914 Q0.9325,0.7274,0.9331,0.7672 Z M0.3191,0.0677 Q0.2943,0.0446,0.2643,0.0317 T0.2066,0.0188 Q0.1795,0.0188,0.1497,0.0317 T0.0949,0.0667 T0.0537,0.122 T0.0375,0.1925 Q0.0375,0.2645,0.0941,0.3167 Q0.1189,0.3398,0.1489,0.353 T0.2066,0.3661 Q0.2337,0.3661,0.2634,0.353 T0.3182,0.3177 T0.3595,0.2624 T0.3756,0.1925 Q0.3756,0.1204,0.3191,0.0677 Z M0.026,0.1957 L0.026,0.1925 Q0.026,0.1161,0.0854,0.0602 Q0.0554,0.0844,0.0381,0.118 T0.0202,0.1903 Z M0.0271,0.2118 L0.0208,0.2059 Q0.0254,0.2645,0.0681,0.3086 Q0.0664,0.3054,0.0646,0.3016 Q0.0329,0.2608,0.0271,0.2118 Z M0.3866,0.2048 Q0.382,0.2737,0.3278,0.3242 Q0.3849,0.279,0.3918,0.2097 Z M0.3872,0.1903 L0.393,0.1952 L0.393,0.1925 Q0.393,0.1581,0.3791,0.1263 Q0.3739,0.1199,0.3681,0.114 Q0.3866,0.15,0.3872,0.1903 Z M0.865,0.0677 Q0.8402,0.0446,0.8102,0.0317 T0.7525,0.0188 Q0.7253,0.0188,0.6956,0.0317 T0.6408,0.0667 T0.5995,0.122 T0.5834,0.1925 Q0.5834,0.2645,0.6399,0.3167 Q0.6647,0.3398,0.6947,0.353 T0.7525,0.3661 Q0.7796,0.3661,0.8093,0.353 T0.8641,0.3177 T0.9054,0.2624 T0.9215,0.1925 Q0.9215,0.1204,0.865,0.0677 Z M0.5718,0.1957 L0.5718,0.1925 Q0.5718,0.1161,0.6313,0.0602 Q0.6013,0.0844,0.584,0.118 T0.5661,0.1903 Z M0.573,0.2118 L0.5666,0.2059 Q0.5713,0.2645,0.614,0.3086 Q0.6122,0.3054,0.6105,0.3016 Q0.5788,0.2608,0.573,0.2118 Z M0.9325,0.2048 Q0.9279,0.2737,0.8736,0.3242 Q0.9308,0.279,0.9377,0.2097 Z M0.9331,0.1898 L0.9388,0.1952 L0.9388,0.1925 Q0.9388,0.1575,0.925,0.1263 Q0.9198,0.1199,0.914,0.114 Q0.9325,0.15,0.9331,0.1898 Z",type:0}},"\uE0D1":{type:5,data:{d:"M0.7639,0.1974 L0.9593,0.1974 L0.9593,0.1443 L0.7639,0.1443 L0.7639,0.1974 Z M0.7586,0.109 L0.9727,0.109 Q0.9839,0.109,0.992,0.1153 T1,0.1291 L1,0.382 Q1,0.3906,0.9912,0.3964 T0.9727,0.4021 L0.7586,0.4021 Q0.7468,0.4021,0.739,0.3956 T0.7313,0.382 L0.7313,0.1291 Q0.7313,0.1246,0.7339,0.1207 T0.7406,0.1143 T0.7495,0.1104 T0.7586,0.109 Z M0.7639,0.6575 L0.9593,0.6575 L0.9593,0.6044 L0.7639,0.6044 L0.7639,0.6575 Z M0.7313,0.8347 L0.7313,0.5843 Q0.7313,0.5757,0.7401,0.5699 T0.7586,0.5641 L0.9706,0.5641 Q0.9818,0.5641,0.9898,0.5705 T0.9979,0.5843 L0.9979,0.8347 Q0.9979,0.8433,0.989,0.8491 T0.9706,0.8549 L0.7586,0.8549 Q0.7468,0.8549,0.739,0.8483 T0.7313,0.8347 Z M0,1 L0,0 L0.7607,0 L0.7607,1 L0,1 Z",type:0}},"\uE0D2":{type:5,data:{d:"M0.9764,0.0029 L0.3179,0.4552 L0,0.4552 L0,0 Z M1,1 L0,1 L0,0.5448 L0.3091,0.5448 Z",type:0}},"\uE0D4":{type:5,data:{d:"M0.0236,0.0029 L0.6824,0.4552 L1,0.4552 L1,0 Z M0,1 L1,1 L1,0.5448 L0.6912,0.5448 Z",type:0}},"\uEE00":{type:3,data:"M0,0 L1,0 L1,.05 L.1,.05 L.1,.95 L1,.95 L1,1 L0,1 Z"},"\uEE01":{type:3,data:"M0,0 L1,0 L1,.05 L0,.05 Z M0,.95 L1,.95 L1,1 L0,1 Z"},"\uEE02":{type:3,data:"M1,0 L0,0 L0,.05 L.9,.05 L.9,.95 L0,.95 L0,1 L1,1 Z"},"\uEE03":{type:3,data:"M0,0 L1,0 L1,.05 L.1,.05 L.1,.95 L1,.95 L1,1 L0,1 Z M.25,.15 L1,.15 L1,.85 L.25,.85 Z"},"\uEE04":{type:3,data:"M0,0 L1,0 L1,.05 L0,.05 Z M0,.95 L1,.95 L1,1 L0,1 Z M0,.15 L1,.15 L1,.85 L0,.85 Z"},"\uEE05":{type:3,data:"M1,0 L0,0 L0,.05 L.9,.05 L.9,.95 L0,.95 L0,1 L1,1 Z M0,.15 L.75,.15 L.75,.85 L0,.85 Z"},"\uEE06":{type:5,data:{d:"M0.6574,0.303 Q0.623,0.291,0.5852,0.285 T0.5082,0.279 T0.4311,0.285 T0.359,0.303 L0.3082,0.248 Q0.3525,0.232,0.4041,0.2235 T0.5082,0.215 T0.6123,0.2235 T0.7082,0.248 Z",type:0},scaleType:1},"\uEE07":{type:5,data:{d:"M0.8557,0.582 L0.7656,0.551 Q0.7852,0.53,0.7951,0.507 T0.8049,0.46 Q0.8049,0.424,0.782,0.3905 T0.718,0.332 T0.6221,0.293 T0.5082,0.279 L0.5082,0.215 Q0.5607,0.215,0.6123,0.2235 T0.709,0.248 T0.7918,0.287 T0.8557,0.3375 T0.8959,0.3965 T0.9098,0.46 T0.8959,0.5235 T0.8557,0.582 Z",type:0},scaleType:1},"\uEE08":{type:5,data:{d:"M0.5082,0.705 Q0.482,0.705,0.4557,0.703 T0.4049,0.697 L0.4311,0.635 Q0.4508,0.638,0.4697,0.6395 T0.5082,0.641 Q0.5672,0.641,0.6221,0.627 T0.718,0.588 T0.782,0.5295 T0.8049,0.46 Q0.8049,0.436,0.7951,0.413 T0.7656,0.369 L0.8557,0.338 Q0.882,0.365,0.8959,0.3965 T0.9098,0.46 T0.8959,0.5235 T0.8557,0.5825 T0.7918,0.633 T0.709,0.672 T0.6123,0.6965 T0.5082,0.705 Z",type:0},scaleType:1},"\uEE09":{type:5,data:{d:"M0.5082,0.705 Q0.4557,0.705,0.4041,0.6965 T0.3074,0.672 T0.2246,0.633 T0.1607,0.5825 T0.1205,0.5235 T0.1066,0.46 L0.2115,0.46 Q0.2115,0.496,0.2344,0.5295 T0.2984,0.588 T0.3943,0.627 T0.5082,0.641 T0.6221,0.627 T0.718,0.588 T0.782,0.5295 T0.8049,0.46 L0.9098,0.46 Q0.9098,0.492,0.8959,0.5235 T0.8557,0.5825 T0.7918,0.633 T0.709,0.672 T0.6123,0.6965 T0.5082,0.705 Z",type:0},scaleType:1},"\uEE0A":{type:5,data:{d:"M0.5082,0.705 Q0.4557,0.705,0.4041,0.6965 T0.3074,0.672 T0.2246,0.633 T0.1607,0.5825 T0.1205,0.5235 T0.1066,0.46 T0.1205,0.3965 T0.1607,0.338 L0.2508,0.369 Q0.2311,0.39,0.2213,0.413 T0.2115,0.46 Q0.2115,0.496,0.2344,0.5295 T0.2984,0.588 T0.3943,0.627 T0.5082,0.641 Q0.5279,0.641,0.5467,0.6395 T0.5852,0.635 L0.6115,0.697 Q0.5869,0.701,0.5607,0.703 T0.5082,0.705 Z",type:0},scaleType:1},"\uEE0B":{type:5,data:{d:"M0.1607,0.582 Q0.1344,0.555,0.1205,0.5235 T0.1066,0.46 T0.1205,0.3965 T0.1607,0.3375 T0.2246,0.287 T0.3074,0.248 T0.4041,0.2235 T0.5082,0.215 L0.5082,0.279 Q0.4492,0.279,0.3943,0.293 T0.2984,0.332 T0.2344,0.3905 T0.2115,0.46 Q0.2115,0.484,0.2213,0.507 T0.2508,0.551 Z",type:0},scaleType:1},"\uF5D0":i2.LINE_H,"\uF5D1":i2.LINE_V,"\uF5D2":i2.FADE_RIGHT,"\uF5D3":i2.FADE_LEFT,"\uF5D4":i2.FADE_DOWN,"\uF5D5":i2.FADE_UP,"\uF5D6":i2.CURVE_DOWN_RIGHT,"\uF5D7":i2.CURVE_DOWN_LEFT,"\uF5D8":i2.CURVE_UP_RIGHT,"\uF5D9":i2.CURVE_UP_LEFT,"\uF5DA":[i2.LINE_V,i2.CURVE_UP_RIGHT],"\uF5DB":[i2.LINE_V,i2.CURVE_DOWN_RIGHT],"\uF5DC":[i2.CURVE_DOWN_RIGHT,i2.CURVE_UP_RIGHT],"\uF5DD":[i2.LINE_V,i2.CURVE_UP_LEFT],"\uF5DE":[i2.LINE_V,i2.CURVE_DOWN_LEFT],"\uF5DF":[i2.CURVE_DOWN_LEFT,i2.CURVE_UP_LEFT],"\uF5E0":[i2.LINE_H,i2.CURVE_DOWN_LEFT],"\uF5E1":[i2.LINE_H,i2.CURVE_DOWN_RIGHT],"\uF5E2":[i2.CURVE_DOWN_LEFT,i2.CURVE_DOWN_RIGHT],"\uF5E3":[i2.LINE_H,i2.CURVE_UP_LEFT],"\uF5E4":[i2.LINE_H,i2.CURVE_UP_RIGHT],"\uF5E5":[i2.CURVE_UP_LEFT,i2.CURVE_UP_RIGHT],"\uF5E6":[i2.LINE_V,i2.CURVE_UP_LEFT,i2.CURVE_UP_RIGHT],"\uF5E7":[i2.LINE_V,i2.CURVE_DOWN_LEFT,i2.CURVE_DOWN_RIGHT],"\uF5E8":[i2.LINE_H,i2.CURVE_DOWN_LEFT,i2.CURVE_UP_LEFT],"\uF5E9":[i2.LINE_H,i2.CURVE_DOWN_RIGHT,i2.CURVE_UP_RIGHT],"\uF5EA":[i2.LINE_V,i2.CURVE_DOWN_RIGHT,i2.CURVE_UP_LEFT],"\uF5EB":[i2.LINE_V,i2.CURVE_DOWN_LEFT,i2.CURVE_UP_RIGHT],"\uF5EC":[i2.LINE_H,i2.CURVE_DOWN_RIGHT,i2.CURVE_UP_LEFT],"\uF5ED":[i2.LINE_H,i2.CURVE_DOWN_LEFT,i2.CURVE_UP_RIGHT],"\uF5EE":[i2.NODE_FILL,i2.NODE_STROKE],"\uF5EF":i2.NODE_STROKE,"\uF5F0":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_RIGHT],"\uF5F1":[i2.NODE_STROKE,i2.NODE_LINE_RIGHT],"\uF5F2":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_LEFT],"\uF5F3":[i2.NODE_STROKE,i2.NODE_LINE_LEFT],"\uF5F4":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF5F5":[i2.NODE_STROKE,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF5F6":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_DOWN],"\uF5F7":[i2.NODE_STROKE,i2.NODE_LINE_DOWN],"\uF5F8":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP],"\uF5F9":[i2.NODE_STROKE,i2.NODE_LINE_UP],"\uF5FA":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_UP],"\uF5FB":[i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_UP],"\uF5FC":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_RIGHT],"\uF5FD":[i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_RIGHT],"\uF5FE":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT],"\uF5FF":[i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT],"\uF600":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_RIGHT],"\uF601":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_RIGHT],"\uF602":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_LEFT],"\uF603":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_LEFT],"\uF604":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_RIGHT],"\uF605":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_RIGHT],"\uF606":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT],"\uF607":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT],"\uF608":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF609":[i2.NODE_STROKE,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF60A":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF60B":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF60C":[i2.NODE_FILL,i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\uF60D":[i2.NODE_STROKE,i2.NODE_LINE_UP,i2.NODE_LINE_DOWN,i2.NODE_LINE_LEFT,i2.NODE_LINE_RIGHT],"\u{1FB00}":s2(1),"\u{1FB01}":s2(2),"\u{1FB02}":s2(3),"\u{1FB03}":s2(4),"\u{1FB04}":s2(5),"\u{1FB05}":s2(6),"\u{1FB06}":s2(7),"\u{1FB07}":s2(8),"\u{1FB08}":s2(9),"\u{1FB09}":s2(10),"\u{1FB0A}":s2(11),"\u{1FB0B}":s2(12),"\u{1FB0C}":s2(13),"\u{1FB0D}":s2(14),"\u{1FB0E}":s2(15),"\u{1FB0F}":s2(16),"\u{1FB10}":s2(17),"\u{1FB11}":s2(18),"\u{1FB12}":s2(19),"\u{1FB13}":s2(20),"\u{1FB14}":s2(22),"\u{1FB15}":s2(23),"\u{1FB16}":s2(24),"\u{1FB17}":s2(25),"\u{1FB18}":s2(26),"\u{1FB19}":s2(27),"\u{1FB1A}":s2(28),"\u{1FB1B}":s2(29),"\u{1FB1C}":s2(30),"\u{1FB1D}":s2(31),"\u{1FB1E}":s2(32),"\u{1FB1F}":s2(33),"\u{1FB20}":s2(34),"\u{1FB21}":s2(35),"\u{1FB22}":s2(36),"\u{1FB23}":s2(37),"\u{1FB24}":s2(38),"\u{1FB25}":s2(39),"\u{1FB26}":s2(40),"\u{1FB27}":s2(41),"\u{1FB28}":s2(43),"\u{1FB29}":s2(44),"\u{1FB2A}":s2(45),"\u{1FB2B}":s2(46),"\u{1FB2C}":s2(47),"\u{1FB2D}":s2(48),"\u{1FB2E}":s2(49),"\u{1FB2F}":s2(50),"\u{1FB30}":s2(51),"\u{1FB31}":s2(52),"\u{1FB32}":s2(53),"\u{1FB33}":s2(54),"\u{1FB34}":s2(55),"\u{1FB35}":s2(56),"\u{1FB36}":s2(57),"\u{1FB37}":s2(58),"\u{1FB38}":s2(59),"\u{1FB39}":s2(60),"\u{1FB3A}":s2(61),"\u{1FB3B}":s2(62),"\u{1FB3C}":{type:3,data:"M0,0.6667 L0,1 L0.5,1 Z"},"\u{1FB3D}":{type:3,data:"M0,0.6667 L0,1 L1,1 Z"},"\u{1FB3E}":{type:3,data:"M0,0.3333 L0,1 L0.5,1 Z"},"\u{1FB3F}":{type:3,data:"M0,0.3333 L0,1 L1,1 Z"},"\u{1FB40}":{type:3,data:"M0,0 L0,1 L0.5,1 Z"},"\u{1FB41}":{type:3,data:"M0,0.3333 L0.5,0 L1,0 L1,1 L0,1 Z"},"\u{1FB42}":{type:3,data:"M0,0.3333 L1,0 L1,1 L0,1 Z"},"\u{1FB43}":{type:3,data:"M0,0.6667 L0.5,0 L1,0 L1,1 L0,1 Z"},"\u{1FB44}":{type:3,data:"M0,0.6667 L1,0 L1,1 L0,1 Z"},"\u{1FB45}":{type:3,data:"M0,1 L0.5,0 L1,0 L1,1 Z"},"\u{1FB46}":{type:3,data:"M0,0.6667 L1,0.3333 L1,1 L0,1 Z"},"\u{1FB47}":{type:3,data:"M0.5,1 L1,0.6667 L1,1 Z"},"\u{1FB48}":{type:3,data:"M0,1 L1,0.6667 L1,1 Z"},"\u{1FB49}":{type:3,data:"M0.5,1 L1,0.3333 L1,1 Z"},"\u{1FB4A}":{type:3,data:"M0,1 L1,0.3333 L1,1 Z"},"\u{1FB4B}":{type:3,data:"M0.5,1 L1,0 L1,1 Z"},"\u{1FB4C}":{type:3,data:"M0.5,0 L0,0 L0,1 L1,1 L1,0.3333 Z"},"\u{1FB4D}":{type:3,data:"M0,0 L0,1 L1,1 L1,0.3333 Z"},"\u{1FB4E}":{type:3,data:"M0.5,0 L0,0 L0,1 L1,1 L1,0.6667 Z"},"\u{1FB4F}":{type:3,data:"M0,0 L0,1 L1,1 L1,0.6667 Z"},"\u{1FB50}":{type:3,data:"M0.5,0 L0,0 L0,1 L1,1 Z"},"\u{1FB51}":{type:3,data:"M0,0.3333 L0,1 L1,1 L1,0.6667 Z"},"\u{1FB52}":{type:3,data:"M0,0.6667 L0.5,1 L1,1 L1,0 L0,0 Z"},"\u{1FB53}":{type:3,data:"M0,0.6667 L1,1 L1,0 L0,0 Z"},"\u{1FB54}":{type:3,data:"M0,0.3333 L0.5,1 L1,1 L1,0 L0,0 Z"},"\u{1FB55}":{type:3,data:"M0,0.3333 L1,1 L1,0 L0,0 Z"},"\u{1FB56}":{type:3,data:"M0,0 L0.5,1 L1,1 L1,0 Z"},"\u{1FB57}":{type:3,data:"M0,0.3333 L0,0 L0.5,0 Z"},"\u{1FB58}":{type:3,data:"M0,0.3333 L0,0 L1,0 Z"},"\u{1FB59}":{type:3,data:"M0,0.6667 L0,0 L0.5,0 Z"},"\u{1FB5A}":{type:3,data:"M0,0.6667 L0,0 L1,0 Z"},"\u{1FB5B}":{type:3,data:"M0,1 L0,0 L0.5,0 Z"},"\u{1FB5C}":{type:3,data:"M0,0.6667 L0,0 L1,0 L1,0.3333 Z"},"\u{1FB5D}":{type:3,data:"M0.5,1 L0,1 L0,0 L1,0 L1,0.6667 Z"},"\u{1FB5E}":{type:3,data:"M0,1 L0,0 L1,0 L1,0.6667 Z"},"\u{1FB5F}":{type:3,data:"M0.5,1 L0,1 L0,0 L1,0 L1,0.3333 Z"},"\u{1FB60}":{type:3,data:"M0,1 L0,0 L1,0 L1,0.3333 Z"},"\u{1FB61}":{type:3,data:"M0.5,1 L0,1 L0,0 L1,0 Z"},"\u{1FB62}":{type:3,data:"M0.5,0 L1,0 L1,0.3333 Z"},"\u{1FB63}":{type:3,data:"M0,0 L1,0 L1,0.3333 Z"},"\u{1FB64}":{type:3,data:"M0.5,0 L1,0 L1,0.6667 Z"},"\u{1FB65}":{type:3,data:"M0,0 L1,0 L1,0.6667 Z"},"\u{1FB66}":{type:3,data:"M0.5,0 L1,0 L1,1 Z"},"\u{1FB67}":{type:3,data:"M0,0.3333 L1,0.6667 L1,0 L0,0 Z"},"\u{1FB68}":{type:3,data:"M0,0 L1,0 L1,1 L0,1 L0.5,0.5 Z"},"\u{1FB69}":{type:3,data:"M0,0 L0.5,0.5 L1,0 L1,1 L0,1 Z"},"\u{1FB6A}":{type:3,data:"M0,0 L1,0 L0.5,0.5 L1,1 L0,1 Z"},"\u{1FB6B}":{type:3,data:"M0,0 L1,0 L1,1 L0.5,0.5 L0,1 Z"},"\u{1FB6C}":{type:3,data:"M0,0 L0.5,0.5 L0,1 Z"},"\u{1FB6D}":{type:3,data:"M0,0 L1,0 L0.5,0.5 Z"},"\u{1FB6E}":{type:3,data:"M1,0 L1,1 L0.5,0.5 Z"},"\u{1FB6F}":{type:3,data:"M0,1 L1,1 L0.5,0.5 Z"},"\u{1FB70}":{type:0,data:[{x:1,y:0,w:1,h:8}]},"\u{1FB71}":{type:0,data:[{x:2,y:0,w:1,h:8}]},"\u{1FB72}":{type:0,data:[{x:3,y:0,w:1,h:8}]},"\u{1FB73}":{type:0,data:[{x:4,y:0,w:1,h:8}]},"\u{1FB74}":{type:0,data:[{x:5,y:0,w:1,h:8}]},"\u{1FB75}":{type:0,data:[{x:6,y:0,w:1,h:8}]},"\u{1FB76}":{type:0,data:[{x:0,y:1,w:8,h:1}]},"\u{1FB77}":{type:0,data:[{x:0,y:2,w:8,h:1}]},"\u{1FB78}":{type:0,data:[{x:0,y:3,w:8,h:1}]},"\u{1FB79}":{type:0,data:[{x:0,y:4,w:8,h:1}]},"\u{1FB7A}":{type:0,data:[{x:0,y:5,w:8,h:1}]},"\u{1FB7B}":{type:0,data:[{x:0,y:6,w:8,h:1}]},"\u{1FB7C}":{type:0,data:[{x:0,y:0,w:1,h:8},{x:0,y:7,w:8,h:1}]},"\u{1FB7D}":{type:0,data:[{x:0,y:0,w:1,h:8},{x:0,y:0,w:8,h:1}]},"\u{1FB7E}":{type:0,data:[{x:7,y:0,w:1,h:8},{x:0,y:0,w:8,h:1}]},"\u{1FB7F}":{type:0,data:[{x:7,y:0,w:1,h:8},{x:0,y:7,w:8,h:1}]},"\u{1FB80}":{type:0,data:[{x:0,y:0,w:8,h:1},{x:0,y:7,w:8,h:1}]},"\u{1FB81}":{type:0,data:[{x:0,y:0,w:8,h:1},{x:0,y:2,w:8,h:1},{x:0,y:4,w:8,h:1},{x:0,y:7,w:8,h:1}]},"\u{1FB82}":{type:0,data:[{x:0,y:0,w:8,h:2}]},"\u{1FB83}":{type:0,data:[{x:0,y:0,w:8,h:3}]},"\u{1FB84}":{type:0,data:[{x:0,y:0,w:8,h:5}]},"\u{1FB85}":{type:0,data:[{x:0,y:0,w:8,h:6}]},"\u{1FB86}":{type:0,data:[{x:0,y:0,w:8,h:7}]},"\u{1FB87}":{type:0,data:[{x:6,y:0,w:2,h:8}]},"\u{1FB88}":{type:0,data:[{x:5,y:0,w:3,h:8}]},"\u{1FB89}":{type:0,data:[{x:3,y:0,w:5,h:8}]},"\u{1FB8A}":{type:0,data:[{x:2,y:0,w:6,h:8}]},"\u{1FB8B}":{type:0,data:[{x:1,y:0,w:7,h:8}]},"\u{1FB8C}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0 L0.5,0 L0.5,1 L0,1 Z"},"\u{1FB8D}":{type:1,data:[[1,0],[0,1]],clipPath:"M0.5,0 L1,0 L1,1 L0.5,1 Z"},"\u{1FB8E}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0 L1,0 L1,0.5 L0,0.5 Z"},"\u{1FB8F}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0.5 L1,0.5 L1,1 L0,1 Z"},"\u{1FB90}":{type:1,data:[[0,1],[1,0]]},"\u{1FB91}":[{type:1,data:[[0,1],[1,0]],clipPath:"M0,0.5 L1,0.5 L1,1 L0,1 Z"},{type:0,data:[{x:0,y:0,w:8,h:4}]}],"\u{1FB92}":[{type:1,data:[[0,1],[1,0]],clipPath:"M0,0 L1,0 L1,0.5 L0,0.5 Z"},{type:0,data:[{x:0,y:4,w:8,h:4}]}],"\u{1FB94}":[{type:1,data:[[0,1],[1,0]],clipPath:"M0,0 L0.5,0 L0.5,1 L0,1 Z"},{type:0,data:[{x:4,y:0,w:4,h:8}]}],"\u{1FB95}":{type:0,data:[{x:0,y:0,w:2,h:2},{x:4,y:0,w:2,h:2},{x:2,y:2,w:2,h:2},{x:6,y:2,w:2,h:2},{x:0,y:4,w:2,h:2},{x:4,y:4,w:2,h:2},{x:2,y:6,w:2,h:2},{x:6,y:6,w:2,h:2}]},"\u{1FB96}":{type:0,data:[{x:2,y:0,w:2,h:2},{x:6,y:0,w:2,h:2},{x:0,y:2,w:2,h:2},{x:4,y:2,w:2,h:2},{x:2,y:4,w:2,h:2},{x:6,y:4,w:2,h:2},{x:0,y:6,w:2,h:2},{x:4,y:6,w:2,h:2}]},"\u{1FB97}":{type:0,data:[{x:0,y:2,w:8,h:2},{x:0,y:6,w:8,h:2}]},"\u{1FB98}":{type:2,data:"M-0.25,-0.25 L1.25,1.25 M-0.25,0 L1,1.25 M-0.25,0.25 L0.75,1.25 M-0.25,0.5 L0.5,1.25 M0,-0.25 L1.25,1 M0.25,-0.25 L1.25,0.75 M0.5,-0.25 L1.25,0.5 M-0.25,0.75 L0.25,1.25 M0.75,-0.25 L1.25,0.25",strokeWidth:1},"\u{1FB99}":{type:2,data:"M-0.25,0.5 L0.5,-0.25 M-0.25,0.75 L0.75,-0.25 M-0.25,1 L1,-0.25 M-0.25,1.25 L1.25,-0.25 M0,1.25 L1.25,0 M0.25,1.25 L1.25,0.25 M0.5,1.25 L1.25,0.5 M-0.25,0.25 L0.25,-0.25 M0.75,1.25 L1.25,0.75",strokeWidth:1},"\u{1FB9A}":{type:5,data:{d:"M0,0 L.5,.5 L0,1 L1,1 L.5,.5 L1,0",type:0}},"\u{1FB9B}":{type:5,data:{d:"M0,0 L.5,.5 L1,0 L1,1 L.5,.5 L0,1",type:0}},"\u{1FB9C}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0 L1,0 L0,1 Z"},"\u{1FB9D}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0 L1,0 L1,1 Z"},"\u{1FB9E}":{type:1,data:[[1,0],[0,1]],clipPath:"M1,0 L1,1 L0,1 Z"},"\u{1FB9F}":{type:1,data:[[1,0],[0,1]],clipPath:"M0,0 L1,1 L0,1 Z"},"\u{1FBA0}":{type:2,data:"M.5,0 L0,.5",strokeWidth:1},"\u{1FBA1}":{type:2,data:"M.5,0 L1,.5",strokeWidth:1},"\u{1FBA2}":{type:2,data:"M0,.5 L.5,1",strokeWidth:1},"\u{1FBA3}":{type:2,data:"M1,.5 L.5,1",strokeWidth:1},"\u{1FBA4}":{type:2,data:"M.5,0 L0,.5 L.5,1",strokeWidth:1},"\u{1FBA5}":{type:2,data:"M.5,0 L1,.5 L.5,1",strokeWidth:1},"\u{1FBA6}":{type:2,data:"M0,.5 L.5,1 L1,.5",strokeWidth:1},"\u{1FBA7}":{type:2,data:"M0,.5 L.5,0 L1,.5",strokeWidth:1},"\u{1FBA8}":{type:2,data:"M.5,0 L0,.5 M1,.5 L.5,1",strokeWidth:1},"\u{1FBA9}":{type:2,data:"M.5,0 L1,.5 M0,.5 L.5,1",strokeWidth:1},"\u{1FBAA}":{type:2,data:"M.5,0 L1,.5 L.5,1 L0,.5",strokeWidth:1},"\u{1FBAB}":{type:2,data:"M.5,0 L0,.5 L.5,1 L1,.5",strokeWidth:1},"\u{1FBAC}":{type:2,data:"M0,.5 L.5,0 L1,.5 L.5,1",strokeWidth:1},"\u{1FBAD}":{type:2,data:"M1,.5 L.5,0 L0,.5 L.5,1",strokeWidth:1},"\u{1FBAE}":{type:2,data:"M.5,0 L1,.5 L.5,1 L0,.5 Z",strokeWidth:1},"\u{1FBAF}":{type:2,data:"M0,.5 L1,.5 M.5,.35 L.5,.65",strokeWidth:1},"\u{1FBB0}":{type:3,data:"M0.1,0.2 L0.1,.8 L.4,.6 L.9,0.6 Z",scaleType:1},"\u{1FBB1}":{type:4,data:{d:"M.1,.525 L.35,.675 L.9,.35",type:1},scaleType:1},"\u{1FBB2}":{type:3,data:"M.29,.27 L0.13,.56 L.22,.59 L.35,0.35 L.67,.35 L.57,.57 L.71,.76 L.22,.76 L.42,1 L.53,.98 L.43,.86 L.9,.86 L.71,.6 L1,.6 L1,.52 L.83,.52 L.92,.36 L1,.36 L1,.27Z M.99,.13 A.12,.12,0,1,1,.75,.13 A.12,.12,0,1,1,.99,.13"},"\u{1FBB3}":{type:3,data:"M0,.27 L.3,.27 L.55,.12 L.63,.18 L.33,.36 L0,.36 M0,.52 L.33,.52 L.59,.89 L.73,.89 L.73,.98 L.53,.98 L.28,.6 L0,.6"},"\u{1FBB4}":{type:4,data:{d:"M.15,.55 L.5,.4 L.5,.45 L.65,.45 L.65,.35 L.85,.35 L.85,.625 L.5,.625 L.5,.7 Z",type:0},scaleType:1},"\u{1FBB5}":[{type:5,data:{d:"M0,0 L1,0 L1,.0625 L0,.0625 Z M0,.9375 L1,.9375 L1,1 L0,1 Z",type:0}},{type:5,data:{d:"M.15,.5 L.5,.35 L.5,.425 L.85,.425 L.85,.575 L.5,.575 L.5,.65 Z",type:0},scaleType:1}],"\u{1FBB6}":[{type:5,data:{d:"M0,0 L1,0 L1,.0625 L0,.0625 Z M0,.9375 L1,.9375 L1,1 L0,1 Z",type:0}},{type:5,data:{d:"M.85,.5 L.5,.35 L.5,.425 L.15,.425 L.15,.575 L.5,.575 L.5,.65 Z",type:0},scaleType:1}],"\u{1FBB7}":[{type:5,data:{d:"M.875,0 L1,0 L1,1 L.875,1 Z",type:0}},{type:5,data:{d:"M.5,.675 L.2,.5 L.35,.5 L.35,.325 L.65,.325 L.65,.5 L.8,.5 Z",type:0},scaleType:1}],"\u{1FBB8}":[{type:5,data:{d:"M.875,0 L1,0 L1,1 L.875,1 Z",type:0}},{type:5,data:{d:"M.5,.325 L.2,.5 L.35,.5 L.35,.675 L.65,.675 L.65,.5 L.8,.5 Z",type:0},scaleType:1}],"\u{1FBB9}":{type:5,data:{d:"M1,.89 L.11,.89 L.11,.37 L.36,.12 L.74,.12 L.96,.34 L1,.34 L1,.405 L.92,.405 L.69,.185 L.41,.185 L.21,.42 L.21,.825 L1,.825 Z",type:0}},"\u{1FBBA}":{type:5,data:{d:"M0,.89 L0,.825 L.78,.825 L.78,.53 L.7,.415 L0,.415 L0,.35 L.75,.35 L.88,.48 L.88,.89 Z",type:0}},"\u{1FBBB}":{type:5,data:{d:"M.31,.275 L.44,.275 L.44,.47 L.05,.47 L.05,.405 L.31,.405 Z M.56,.275 L.69,.275 L.69,.405 L.95,.405 L.95,.47 L.56,.47 Z M.05,.53 L.44,.53 L.44,.725 L.31,.725 L.31,.595 L.05,.595 Z M.56,.53 L.95,.53 L.95,.595 L.69,.595 L.69,.725 L.56,.725 Z",type:0},scaleType:1},"\u{1FBBC}":[{type:3,data:"M0,0 L1,0 L1,1 L0,1 L0,.935 L.885,.935 L.885,.065 L0,.065 Z"},{type:3,data:"M.67,.5 A.17,.085,0,1,1,.33,.5 A.17,.085,0,1,1,.67,.5",scaleType:1}],"\u{1FBBD}":{type:4,data:{d:"M0,0 L.5,.5 L1,0 L1,1 L.5,.5 L0,1 Z",type:1}},"\u{1FBBE}":{type:4,data:{d:"M1,.5 L.5,1",type:1}},"\u{1FBBF}":{type:4,data:{d:"M.5,0 L1,.5 L.5,1 L0,.5 Z",type:1}},"\u{1FBC0}":{type:3,data:"M.16,.445 A.02,.01,0,0,1,.39,.33 L.5,.375 L.61,.33 A.02,.01,0,0,1,.84,.445 L.75,.5 L.84,.555 A.02,.01,0,0,1,.61,.67 L.5,.625 L.39,.67 A.02,.01,0,0,1,.16,.555 L.25,.5 Z M.24,.41 L.39,.5 L.24,.59 L.32,.63 L.5,.555 L.68,.63 L.76,.59 L.61,.5 L.76,.41 L.68,.37 L.5,.445 L.32,.37 Z",scaleType:1},"\u{1FBC1}":{type:3,data:"M0.142308,0.924 Q0.130770,0.924,0.120193,0.922 T0.101924,0.916 T0.089424,0.9065 T0.084616,0.895 V0.025 Q0.084616,0.019,0.089424,0.0135 T0.101924,0.004 T0.120193,-0.002 T0.142308,-0.004 Q0.150000,-0.004,0.157693,-0.003 T0.173078,0.000 L0.430770,0.085 Q0.451924,0.059,0.494232,0.041 T0.587501,0.013 T0.692309,-0.0005 T0.800001,-0.004 H1 V0.055 H0.800001 Q0.771155,0.055,0.742309,0.056 T0.685578,0.060 T0.630770,0.0685 T0.580770,0.0825 T0.543270,0.1045 T0.528847,0.133 V0.647 H0.530770 Q0.596155,0.645,0.659616,0.638 T0.782693,0.6165 T0.893270,0.5805 T1,0.531 V0.623 Q0.934616,0.644,0.880770,0.6595 T0.769232,0.685 T0.650963,0.700 T0.528847,0.707 V0.787 Q0.528847,0.802,0.543270,0.8155 T0.580770,0.8375 T0.630770,0.8515 T0.685578,0.860 T0.742309,0.864 T0.800001,0.865 H1 V0.924 H0.800001 Q0.746155,0.924,0.692309,0.9205 T0.587501,0.907 T0.494232,0.879 T0.430770,0.835 L0.173078,0.920 Q0.165386,0.922,0.157693,0.923 T0.142308,0.924 Z M0.2,0.841 L0.415385,0.770 V0.150 L0.2,0.079 V0.841 Z M1,0.698 Q0.973077,0.694,0.969231,0.6885 T0.965385,0.677 Q0.965385,0.672,0.969231,0.6665 T1,0.657 V0.698 Z"},"\u{1FBC2}":{type:3,data:"M0,0.623 V0.531 Q0.044231,0.512,0.0625,0.4905 T0.092308,0.4465 T0.108654,0.4005 T0.113462,0.354 V0.351 Q0.113462,0.345,0.117308,0.3395 T0.129808,0.3305 T0.148846,0.3245 T0.171154,0.323 H0.501923 Q0.532692,0.323,0.563462,0.3185 T0.617308,0.303 T0.651923,0.2765 T0.663462,0.2435 V0.241 Q0.663462,0.219,0.657692,0.197 T0.639423,0.1545 T0.604808,0.115 T0.549615,0.082 T0.475577,0.0615 T0.392308,0.055 H0 V-0.004 H1 V0.055 H0.667308 Q0.694231,0.071,0.713462,0.09 T0.746154,0.129 T0.766346,0.1705 T0.775,0.213 H1 V0.316 Q0.971154,0.305,0.955769,0.2965 T0.920192,0.2825 T0.876923,0.2745 T0.830769,0.272 H0.773077 Q0.767308,0.297,0.743269,0.319 T0.680769,0.355 T0.595192,0.375 T0.501923,0.381 H0.227308 Q0.223462,0.415,0.211,0.4485 T0.172692,0.5135 T0.108269,0.573 T0,0.623 Z M0.611538,0.924 H0 V0.865 H0.611538 Q0.642308,0.865,0.673077,0.8605 T0.727885,0.845 T0.762308,0.8185 T0.773077,0.787 V0.785 Q0.773077,0.769,0.762308,0.7535 T0.727885,0.727 T0.673077,0.7115 T0.611538,0.707 H0.059615 Q0.048077,0.707,0.037115,0.7045 T0,0.694 V0.653 Q0.026923,0.648,0.037115,0.646 T0.059615,0.644 H0.722692 Q0.753462,0.644,0.784231,0.6395 T0.839038,0.624 T0.873846,0.5975 T0.884615,0.566 V0.564 Q0.884615,0.548,0.873846,0.532 T0.839038,0.5055 T0.784231,0.49 T0.722692,0.4855 H0.392308 Q0.380769,0.4855,0.370192,0.483 T0.351923,0.4765 T0.339423,0.467 T0.334615,0.4555 T0.339423,0.444 T0.351923,0.4345 T0.370192,0.428 T0.392308,0.4255 H0.832692 Q0.855769,0.4255,0.878846,0.4235 T0.922115,0.416 T0.957692,0.4015 T1,0.3815 V0.4685 Q0.975,0.4705,0.966346,0.4725 T0.95,0.4765 Q0.961538,0.4835,0.969231,0.4915 T1,0.5075 V0.6205 Q0.965385,0.6455,0.926923,0.665 T0.84,0.6935 Q0.866923,0.7115,0.877596,0.7345 T0.894231,0.7855 V0.787 Q0.894231,0.815,0.876923,0.8425 T0.820192,0.8895 T0.726923,0.916 T0.611538,0.924 Z"},"\u{1FBC3}":{type:3,data:"M0,0.473 V0.386 Q0.025490,0.378,0.028431,0.3695 T0.031373,0.352 V0.35 Q0.031373,0.342,0.028431,0.333 T0,0.316 V0.213 H0.652941 Q0.684314,0.213,0.715686,0.2085 T0.770588,0.193 T0.804902,0.1665 T0.815686,0.135 V0.133 Q0.815686,0.117,0.804902,0.101 T0.770588,0.0745 T0.715686,0.0595 T0.652941,0.055 H0 V-0.004 H0.652941 Q0.707843,-0.004,0.761765,0.004 T0.856863,0.031 T0.915686,0.0775 T0.933333,0.133 V0.135 Q0.933333,0.163,0.915686,0.1905 T0.856863,0.237 T0.761765,0.264 T0.652941,0.272 H0.109804 Q0.131373,0.29,0.140196,0.31 T0.149020,0.35 V0.352 Q0.149020,0.37,0.142157,0.388 T0.118627,0.4225 T0.076471,0.452 T0,0.473 Z M0,0.625 V0.513 Q0.029412,0.526,0.032353,0.54 T0.035294,0.568 V0.57 Q0.035294,0.584,0.032353,0.598 T0,0.625 Z"},"\u{1FBC4}":{type:3,data:"M0.019231,1.085 V-0.165 H0.980769 V1.085 H0.019231 Z M0.446154,0.527 H0.553846 Q0.553846,0.511,0.5625,0.495 T0.591346,0.466 T0.631731,0.4405 T0.666346,0.4135 T0.688462,0.3825 T0.696154,0.35 Q0.696154,0.33,0.682692,0.311 T0.641346,0.2785 T0.575,0.259 T0.498077,0.253 T0.421154,0.259 T0.356731,0.279 T0.315385,0.3125 T0.301923,0.352 V0.357 H0.409615 V0.354 Q0.409615,0.345,0.414423,0.335 T0.431731,0.318 T0.4625,0.3075 T0.498077,0.304 Q0.517308,0.304,0.534615,0.307 T0.564423,0.3165 T0.582692,0.332 T0.588462,0.35 Q0.588462,0.366,0.572115,0.3805 T0.535577,0.4075 T0.496154,0.4335 T0.465385,0.4625 T0.45,0.4945 T0.446154,0.527 Z M0.5,0.667 Q0.519231,0.667,0.5375,0.664 T0.569231,0.654 T0.588462,0.637 T0.594231,0.617 T0.588462,0.5975 T0.569231,0.581 T0.5375,0.571 T0.5,0.568 T0.4625,0.571 T0.430769,0.581 T0.411538,0.5975 T0.405769,0.617 T0.411538,0.637 T0.430769,0.654 T0.4625,0.664 T0.5,0.667 Z",scaleType:1},"\u{1FBC5}":{type:5,data:{d:"M.44,.425 L.44,.51 L.44,.56 L.19,.685 L.26,.72 L.5,.605 L.74,.72 L.81,.685 L.56,.56 L.56,.51 L.56,.425 Z M.17,.46 L.17,.51 L.83,.51 L.83,.46 Z M.67,.35 C.67,.303,.594,.265,.5,.265 C.406,.265,.33,.303,.33,.35 C.33,.397,.406,.435,.5,.435 C.594,.435,.67,.397,.67,.35 Z M.56,.35 C.56,.3665,.533,.38,.5,.38 C.467,.38,.44,.3665,.44,.35 C.44,.3335,.467,.32,.5,.32 C.533,.32,.56,.3335,.56,.35 Z",type:0},scaleType:1},"\u{1FBC6}":{type:5,data:{d:"M.44,.425 L.44,.46 L.23,.385 L.19,.43 L.44,.51 L.44,.56 L.29,.71 L.38,.735 L.5,.605 L.61,.735 L.7,.71 L.56,.56 L.56,.51 L.81,.43 L.77,.385 L.56,.46 L.56,.425 Z M.67,.35 C.67,.303,.594,.265,.5,.265 C.406,.265,.33,.303,.33,.35 C.33,.397,.406,.435,.5,.435 C.594,.435,.67,.397,.67,.35 Z M.56,.35 C.56,.3665,.533,.38,.5,.38 C.467,.38,.44,.3665,.44,.35 C.44,.3335,.467,.32,.5,.32 C.533,.32,.56,.3335,.56,.35 Z",type:0},scaleType:1},"\u{1FBC7}":{type:5,data:{d:"M.44,.425 L.44,.56 L.29,.71 L.38,.735 L.5,.605 L.74,.72 L.81,.685 L.56,.56 L.56,.425 Z M.18,.53 L.23,.575 L.81,.43 L.77,.385 Z M.67,.35 C.67,.303,.594,.265,.5,.265 C.406,.265,.33,.303,.33,.35 C.33,.397,.406,.435,.5,.435 C.594,.435,.67,.397,.67,.35 Z M.56,.35 C.56,.3665,.533,.38,.5,.38 C.467,.38,.44,.3665,.44,.35 C.44,.3335,.467,.32,.5,.32 C.533,.32,.56,.3335,.56,.35 Z",type:0},scaleType:1},"\u{1FBC8}":{type:5,data:{d:"M.44,.425 L.44,.56 L.19,.685 L.26,.72 L.5,.605 L.62,.735 L.71,.71 L.56,.56 L.56,.425 Z M.23,.385 L.18,.43 L.77,.575 L.81,.53 Z M.67,.35 C.67,.303,.594,.265,.5,.265 C.406,.265,.33,.303,.33,.35 C.33,.397,.406,.435,.5,.435 C.594,.435,.67,.397,.67,.35 Z M.56,.35 C.56,.3665,.533,.38,.5,.38 C.467,.38,.44,.3665,.44,.35 C.44,.3335,.467,.32,.5,.32 C.533,.32,.56,.3335,.56,.35 Z",type:0},scaleType:1},"\u{1FBC9}":{type:5,data:{d:"M.44,.425 L.45,.495 L.15,.645 L.34,.645 L.34,.7 L.44,.7 L.44,.645 L.56,.645 L.56,.7 L.66,.7 L.66,.645 L.84,.645 L.54,.495 L.56,.425 Z M.39,.6 L.5,.55 L.60,.6 Z M.17,.46 L.17,.51 L.83,.51 L.83,.46 Z M.67,.35 C.67,.303,.594,.265,.5,.265 C.406,.265,.33,.303,.33,.35 C.33,.397,.406,.435,.5,.435 C.594,.435,.67,.397,.67,.35 Z M.56,.35 C.56,.3665,.533,.38,.5,.38 C.467,.38,.44,.3665,.44,.35 C.44,.3335,.467,.32,.5,.32 C.533,.32,.56,.3335,.56,.35 Z",type:0},scaleType:1},"\u{1FBCA}":{type:5,data:{d:"M.26,.375 L.5,.255 L.74,.375 L.74,.665 L.5,.55 L.26,.665 Z M.37,.395 L.37,.54 L.5,.475 L.63,.54 L.63,.395 L.5,.33 Z",type:0},scaleType:1},"\u{1FBCB}":{type:5,data:{d:"M.09,.41 L.32,.295 L.5,.375 L.68,.295 L.91,.41 L.75,.5 L.91,.59 L.68,.705 L.5,.625 L.32,.705 L.09,.59 L.25,.5 Z M.24,.41 L.39,.5 L.24,.59 L.32,.63 L.5,.555 L.68,.63 L.76,.59 L.61,.5 L.76,.41 L.68,.37 L.5,.445 L.32,.37 Z",type:0},scaleType:1},"\u{1FBCC}":{type:5,data:{d:"M.55,.305 L.88,.305 L.88,.355 L.65,.355 L.65,.47 L.88,.47 L.88,.52 L.55,.52 Z",type:0},scaleType:1},"\u{1FBCD}":{type:5,data:{d:"M.38,.39 L.5,.33 L.62,.39 L.62,.53 L.5,.47 L.38,.53 Z",type:0},scaleType:1},"\u{1FBCE}":{type:3,data:"M0,0 L0.6667,0 L0.6667,1 L0,1 Z"},"\u{1FBCF}":{type:3,data:"M0,0 L0.3333,0 L0.3333,1 L0,1 Z"},"\u{1FBD0}":{type:2,data:"M1,.5 L0,1",strokeWidth:1},"\u{1FBD1}":{type:2,data:"M1,0 L0,.5",strokeWidth:1},"\u{1FBD2}":{type:2,data:"M0,0 L1,.5",strokeWidth:1},"\u{1FBD3}":{type:2,data:"M0,.5 L1,1",strokeWidth:1},"\u{1FBD4}":{type:2,data:"M0,0 L.5,1",strokeWidth:1},"\u{1FBD5}":{type:2,data:"M.5,0 L1,1",strokeWidth:1},"\u{1FBD6}":{type:2,data:"M1,0 L.5,1",strokeWidth:1},"\u{1FBD7}":{type:2,data:"M.5,0 L0,1",strokeWidth:1},"\u{1FBD8}":{type:2,data:"M0,0 L.5,.5 L1,0",strokeWidth:1},"\u{1FBD9}":{type:2,data:"M1,0 L.5,.5 L1,1",strokeWidth:1},"\u{1FBDA}":{type:2,data:"M0,1 L.5,.5 L1,1",strokeWidth:1},"\u{1FBDB}":{type:2,data:"M0,0 L.5,.5 L0,1",strokeWidth:1},"\u{1FBDC}":{type:2,data:"M0,0 L.5,1 L1,0",strokeWidth:1},"\u{1FBDD}":{type:2,data:"M1,0 L0,.5 L1,1",strokeWidth:1},"\u{1FBDE}":{type:2,data:"M0,1 L.5,0 L1,1",strokeWidth:1},"\u{1FBDF}":{type:2,data:"M0,0 L1,.5 L0,1",strokeWidth:1},"\u{1FBE0}":{type:5,data:{d:"M0,0 C0,.276,.224,.5,.5,.5 C.776,.5,1,.276,1,0",type:1}},"\u{1FBE1}":{type:5,data:{d:"M1,0 C.724,0,.5,.224,.5,.5 C.5,.776,.724,1,1,1",type:1}},"\u{1FBE2}":{type:5,data:{d:"M0,1 C0,.724,.224,.5,.5,.5 C.776,.5,1,.724,1,1",type:1}},"\u{1FBE3}":{type:5,data:{d:"M0,0 C.276,0,.5,.224,.5,.5 C.5,.776,.276,1,0,1",type:1}},"\u{1FBE4}":{type:0,data:[{x:2,y:0,w:4,h:4}]},"\u{1FBE5}":{type:0,data:[{x:2,y:4,w:4,h:4}]},"\u{1FBE6}":{type:0,data:[{x:0,y:2,w:4,h:4}]},"\u{1FBE7}":{type:0,data:[{x:4,y:2,w:4,h:4}]},"\u{1FBE8}":{type:5,data:{d:"M0,0 C0,.276,.224,.5,.5,.5 C.776,.5,1,.276,1,0 Z",type:0}},"\u{1FBE9}":{type:5,data:{d:"M1,0 C.724,0,.5,.224,.5,.5 C.5,.776,.724,1,1,1 Z",type:0}},"\u{1FBEA}":{type:5,data:{d:"M0,1 C0,.724,.224,.5,.5,.5 C.776,.5,1,.724,1,1 Z",type:0}},"\u{1FBEB}":{type:5,data:{d:"M0,0 C.276,0,.5,.224,.5,.5 C.5,.776,.276,1,0,1 Z",type:0}},"\u{1FBEC}":{type:5,data:{d:"M1,0 L.5,0 C.5,.276,.724,.5,1,.5 Z",type:0}},"\u{1FBED}":{type:5,data:{d:"M0,1 L.5,1 C.5,.724,.276,.5,0,.5 Z",type:0}},"\u{1FBEE}":{type:5,data:{d:"M1,1 L1,.5 C.724,.5,.5,.724,.5,1 Z",type:0}},"\u{1FBEF}":{type:5,data:{d:"M0,0 L0,.5 C.276,.5,.5,.276,.5,0 Z",type:0}},"\u{1FBF0}":{type:5,data:{d:r(126),type:0},scaleType:1},"\u{1FBF1}":{type:5,data:{d:r(48),type:0},scaleType:1},"\u{1FBF2}":{type:5,data:{d:r(109),type:0},scaleType:1},"\u{1FBF3}":{type:5,data:{d:r(121),type:0},scaleType:1},"\u{1FBF4}":{type:5,data:{d:r(51),type:0},scaleType:1},"\u{1FBF5}":{type:5,data:{d:r(91),type:0},scaleType:1},"\u{1FBF6}":{type:5,data:{d:r(95),type:0},scaleType:1},"\u{1FBF7}":{type:5,data:{d:r(114),type:0},scaleType:1},"\u{1FBF8}":{type:5,data:{d:r(127),type:0},scaleType:1},"\u{1FBF9}":{type:5,data:{d:r(123),type:0},scaleType:1},"\u{1FBFA}":{type:5,data:{d:"M.5,.175 C.2,.175,.15,.305,.15,.435 L.05,.63 L.35,.63 C.35,.682,.42,.76,.5,.76 C.58,.76,.65,.682,.65,.63 L.95,.63 L.85,.435 C.85,.305,.8,.175,.5,.175 Z",type:0},scaleType:1},...Object.fromEntries(Array.from({length:256},(t3,e3)=>[String.fromCodePoint(10240+e3),{type:6,data:e3}]))},e2.blockPatternCodepoints=new Set([9617,9618,9619,129932,129933,129934,129935,129936,129937,129938,129940,129948,129949,129950,129951])},183(t2,e2,i2){;Object.defineProperty(e2,"__esModule",{value:true}),e2.tryDrawCustomGlyph=function(t3,e3,i3,s3,o2,n2,L2,h2,T2,l2,d,c,_=0){const Q=r.customGlyphDefinitions[e3];if(Q){const e4=Array.isArray(Q)?Q:[Q];for(const r2 of e4)a(t3,r2,i3,s3,o2,n2,L2,h2,T2,l2,d,c,_);return true}return false};const s2=i2(959),r=i2(915);function a(t3,e3,i3,r2,a2,h2,d,c,_,Q,u,p,g=0){let M=a2,y=h2,v=i3,f=r2;switch(1===e3.scaleType&&(M=d,y=c,v=i3+(a2-d)/2,f=r2+(h2-c)/2),e3.clipPath&&(t3.save(),(function(t4,e4,i4,s3,r3,a3){t4.beginPath();for(const o2 of e4.split(" ")){const e5=o2[0];if("Z"===e5){t4.closePath();continue}const n2=o2.substring(1).split(",");if(!n2[0]||!n2[1])continue;const L2=i4+parseFloat(n2[0])*r3,h3=s3+parseFloat(n2[1])*a3;"M"===e5?t4.moveTo(L2,h3):"L"===e5&&t4.lineTo(L2,h3)}t4.clip()})(t3,e3.clipPath,v,f,M,y)),e3.type){case 0:!(function(t4,e4,i4,s3,r3,a3){for(let o2=0;o27&&parseInt(T2.slice(7,9),16)||1;else{if(!T2.startsWith("rgba"))throw new Error(`Unexpected fillStyle color format "${T2}" when drawing pattern glyph`);[L2,d3,c3,_2]=T2.substring(5,T2.length-1).split(",").map(t5=>parseFloat(t5))}for(let t5=0;t5>1&1,c2=1&n2;0!==d2||0!==c2?l2.setTransform(new DOMMatrix().translateSelf(-d2,-c2)):l2.setTransform(new DOMMatrix),t4.fillStyle=l2,t4.fillRect(i4,r3,a3,o2)})(t3,e3.data,v,f,M,y,g);break;case 2:!(function(t4,e4,i4,s3,r3,a3,o2,n2,L2){let h3;t4.save(),t4.beginPath(),t4.rect(i4,s3,r3,a3),t4.clip(),t4.beginPath(),h3="function"==typeof e4?e4(.15,.15/a3*r3):e4;const d2={currentX:0,currentY:0,lastControlX:0,lastControlY:0,lastCommand:""};for(const e5 of h3.split(" ")){const L3=e5[0];if("Z"===L3){;t4.closePath(),d2.lastCommand=L3;continue}const h4=T[L3];if(!h4){n2.error(`Could not find drawing instructions for "${L3}"`);continue}const c2=e5.substring(1).split(",");c2[0]&&c2[1]&&(h4(t4,l(c2,r3,a3,i4,s3,true,o2,0,0,false),d2),d2.lastCommand=L3)};void 0!==L2?(t4.strokeStyle=t4.fillStyle,t4.lineWidth=o2*L2,t4.stroke()):t4.fill(),t4.closePath(),t4.restore()})(t3,e3.data,v,f,M,y,Q,u,e3.strokeWidth);break;case 3:!(function(t4,e4,i4,s3,r3,a3,o2,L2){const h3="string"==typeof e4?e4:e4(0,0);t4.beginPath();let T2=0,l2=0,d2=0,c2=0,_2="";for(const e5 of h3.split(" ")){const o3=e5[0],L3=e5.substring(1).split(",");if("Z"===o3){;t4.closePath(),_2=o3;continue}if("V"===o3){const e6=s3+parseFloat(L3[0])*a3;t4.lineTo(T2,e6),l2=e6,d2=T2,c2=l2,_2=o3;continue}if("H"===o3){const e6=i4+parseFloat(L3[0])*r3;t4.lineTo(e6,l2),T2=e6,d2=T2,c2=l2,_2=o3;continue}if(!L3[0]||!L3[1])continue;if("A"===o3){const e6=parseFloat(L3[0])*r3,o4=parseFloat(L3[1])*a3,h5=parseFloat(L3[2])*Math.PI/180,d3=parseInt(L3[3],10),c3=parseInt(L3[4],10),_3=i4+parseFloat(L3[5])*r3,Q2=s3+parseFloat(L3[6])*a3;n(t4,T2,l2,e6,o4,h5,d3,c3,_3,Q2),T2=_3,l2=Q2;continue}const h4=L3.map((t5,e6)=>{const o4=parseFloat(t5);return e6%2==0?i4+o4*r3:s3+o4*a3});if("M"===o3)t4.moveTo(h4[0],h4[1]),T2=h4[0],l2=h4[1],d2=T2,c2=l2;else if("L"===o3)t4.lineTo(h4[0],h4[1]),T2=h4[0],l2=h4[1],d2=T2,c2=l2;else if("Q"===o3)t4.quadraticCurveTo(h4[0],h4[1],h4[2],h4[3]),d2=h4[0],c2=h4[1],T2=h4[2],l2=h4[3];else if("T"===o3){let e6,i5;"Q"===_2||"T"===_2?(e6=2*T2-d2,i5=2*l2-c2):(e6=T2,i5=l2),t4.quadraticCurveTo(e6,i5,h4[0],h4[1]),d2=e6,c2=i5,T2=h4[0],l2=h4[1]}else"C"===o3&&(t4.bezierCurveTo(h4[0],h4[1],h4[2],h4[3],h4[4],h4[5]),d2=h4[2],c2=h4[3],T2=h4[4],l2=h4[5]);_2=o3}void 0!==L2?(t4.strokeStyle=t4.fillStyle,t4.lineWidth=o2*L2,t4.stroke()):t4.fill()})(t3,e3.data,v,f,M,y,Q,e3.strokeWidth);break;case 4:!(function(t4,e4,i4,s3,r3,a3,o2,n2){;t4.save(),t4.fillRect(i4,s3,r3,a3),n2&&(t4.fillStyle=n2,t4.strokeStyle=n2),t4.lineWidth=o2,t4.lineCap="square",t4.beginPath();for(const o3 of e4.d.split(" ")){const e5=o3[0],n3=o3.substring(1).split(",");if(!n3[0]||!n3[1]){"Z"===e5&&t4.closePath();continue}const L2=n3.map((t5,e6)=>{const o4=parseFloat(t5);return e6%2==0?i4+o4*r3:s3+o4*a3});"M"===e5?t4.moveTo(L2[0],L2[1]):"L"===e5&&t4.lineTo(L2[0],L2[1])};1===e4.type?t4.stroke():t4.fill(),t4.restore()})(t3,e3.data,v,f,M,y,Q,p);break;case 5:!(function(t4,e4,i4,s3,r3,a3,o2,n2,L2){const h3=new Path2D;h3.rect(i4,s3,r3,a3),t4.clip(h3),t4.beginPath();const d2=o2/12;t4.lineWidth=n2*d2;const c2={currentX:0,currentY:0,lastControlX:0,lastControlY:0,lastCommand:""};for(const o3 of e4.d.split(" ")){const h4=o3[0];if("Z"===h4){;t4.closePath(),c2.lastCommand=h4;continue}const _2=T[h4];if(!_2){L2.error(`Could not find drawing instructions for "${h4}"`);continue}const Q2=o3.substring(1).split(",");Q2[0]&&Q2[1]&&(_2(t4,l(Q2,r3,a3,i4,s3,false,n2,(e4.leftPadding??0)*(d2/2),(e4.rightPadding??0)*(d2/2)),c2),c2.lastCommand=h4)};1===e4.type?(t4.strokeStyle=t4.fillStyle,t4.stroke()):t4.fill(),t4.closePath()})(t3,e3.data,v,f,M,y,_,Q,u);break;case 6:!(function(t4,e4,i4,s3,r3,a3){const n2=r3/8,L2=.1*a3,h3=.8*a3/8,T2=Math.min(n2,h3);for(let r4=0;r4<8;r4++)if(e4&1<1){const t4=Math.sqrt(y);u=(s3*=t4)*s3,p=(r2*=t4)*r2}let v=(u*p-u*M-p*g)/(u*M+p*g);v<0&&(v=0);const f=(o2===n2?-1:1)*Math.sqrt(v),C=f*(s3*Q/r2),m=f*(-r2*_/s3),w=T2*C-l2*m+(e3+L2)/2,x=l2*C+T2*m+(i3+h2)/2,b=(_-C)/s3,E=(Q-m)/r2,R=(-_-C)/s3,k=(-Q-m)/r2,A=Math.atan2(E,b);let Z=Math.atan2(k,R)-A;0===n2&&Z>0?Z-=2*Math.PI:1===n2&&Z<0&&(Z+=2*Math.PI);const D=A+Z;t3.ellipse(w,x,s3,r2,a2,A,D,0===n2)}const L=new Map;function h(t3,e3,i3=0){return Math.max(Math.min(t3,e3),i3)}const T={C:(t3,e3,i3)=>{;t3.bezierCurveTo(e3[0],e3[1],e3[2],e3[3],e3[4],e3[5]),i3.lastControlX=e3[2],i3.lastControlY=e3[3],i3.currentX=e3[4],i3.currentY=e3[5]},L:(t3,e3,i3)=>{;t3.lineTo(e3[0],e3[1]),i3.lastControlX=i3.currentX=e3[0],i3.lastControlY=i3.currentY=e3[1]},M:(t3,e3,i3)=>{;t3.moveTo(e3[0],e3[1]),i3.lastControlX=i3.currentX=e3[0],i3.lastControlY=i3.currentY=e3[1]},Q:(t3,e3,i3)=>{;t3.quadraticCurveTo(e3[0],e3[1],e3[2],e3[3]),i3.lastControlX=e3[0],i3.lastControlY=e3[1],i3.currentX=e3[2],i3.currentY=e3[3]},T:(t3,e3,i3)=>{let s3,r2;"Q"===i3.lastCommand||"T"===i3.lastCommand?(s3=2*i3.currentX-i3.lastControlX,r2=2*i3.currentY-i3.lastControlY):(s3=i3.currentX,r2=i3.currentY),t3.quadraticCurveTo(s3,r2,e3[0],e3[1]),i3.lastControlX=s3,i3.lastControlY=r2,i3.currentX=e3[0],i3.currentY=e3[1]}};function l(t3,e3,i3,s3,r2,a2,o2,n2=0,L2=0,T2=true){const l2=t3.map(t4=>parseFloat(t4)||parseInt(t4));if(l2.length<2)throw new Error("Too few arguments for instruction");for(let t4=0;t4{;this._refreshCharAtlas(t3,e4),this.reset(t3)})),this._register((0,r.toDisposable)(()=>{this._canvas.remove()}))}_initCanvas(){;this._ctx=(0,a.throwIfFalsy)(this._canvas.getContext("2d",{alpha:this._alpha})),this._alpha||this._clearAll()}handleBlur(t3){}handleFocus(t3){}handleCursorMove(t3){}handleGridChanged(t3,e3,i3){}handleSelectionChanged(t3,e3,i3,s3=false){}_setTransparency(t3,e3){if(e3===this._alpha)return;const i3=this._canvas;this._alpha=e3,this._canvas=this._canvas.cloneNode(),this._initCanvas(),this._container.replaceChild(this._canvas,i3),this._refreshCharAtlas(t3,this._themeService.colors),this.handleGridChanged(t3,0,t3.rows-1)}_refreshCharAtlas(t3,e3){;this._deviceCharWidth<=0&&this._deviceCharHeight<=0||(this._charAtlas=(0,s2.acquireTextureAtlas)(t3,this._optionsService.rawOptions,e3,this._deviceCellWidth,this._deviceCellHeight,this._deviceCharWidth,this._deviceCharHeight,this._coreBrowserService.dpr,2048),this._charAtlas.warmUp())}resize(t3,e3){;this._deviceCellWidth=e3.device.cell.width,this._deviceCellHeight=e3.device.cell.height,this._deviceCharWidth=e3.device.char.width,this._deviceCharHeight=e3.device.char.height,this._deviceCharLeft=e3.device.char.left,this._deviceCharTop=e3.device.char.top,this._canvas.width=e3.device.canvas.width,this._canvas.height=e3.device.canvas.height,this._canvas.style.width=`${e3.css.canvas.width}px`,this._canvas.style.height=`${e3.css.canvas.height}px`,this._alpha||this._clearAll(),this._refreshCharAtlas(t3,this._themeService.colors)}_fillBottomLineAtCells(t3,e3,i3=1){this._ctx.fillRect(t3*this._deviceCellWidth,(e3+1)*this._deviceCellHeight-this._coreBrowserService.dpr-1,i3*this._deviceCellWidth,this._coreBrowserService.dpr)}_clearAll(){this._alpha?this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(0,0,this._canvas.width,this._canvas.height))}_clearCells(t3,e3,i3,s3){this._alpha?this._ctx.clearRect(t3*this._deviceCellWidth,e3*this._deviceCellHeight,i3*this._deviceCellWidth,s3*this._deviceCellHeight):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(t3*this._deviceCellWidth,e3*this._deviceCellHeight,i3*this._deviceCellWidth,s3*this._deviceCellHeight))}_fillCharTrueColor(t3,e3,i3,s3){;this._ctx.font=this._getFont(t3,false,false),this._ctx.textBaseline=o.TEXT_BASELINE,this._clipCell(i3,s3,e3.getWidth()),this._ctx.fillText(e3.getChars(),i3*this._deviceCellWidth+this._deviceCharLeft,s3*this._deviceCellHeight+this._deviceCharTop+this._deviceCharHeight)}_clipCell(t3,e3,i3){;this._ctx.beginPath(),this._ctx.rect(t3*this._deviceCellWidth,e3*this._deviceCellHeight,i3*this._deviceCellWidth,this._deviceCellHeight),this._ctx.clip()}_getFont(t3,e3,i3){return`${i3?"italic":""} ${e3?t3.options.fontWeightBold:t3.options.fontWeight} ${t3.options.fontSize*this._coreBrowserService.dpr}px ${t3.options.fontFamily}`}}e2.BaseRenderLayer=n},306(t2,e2,i2){;Object.defineProperty(e2,"__esModule",{value:true}),e2.LinkRenderLayer=void 0;const s2=i2(657),r=i2(814),a=i2(133);class o extends a.BaseRenderLayer{constructor(t3,e3,i3,s3,r2,a2,o2){;super(i3,t3,"link",e3,true,r2,a2,o2),this._register(s3.onShowLinkUnderline(t4=>this._handleShowLinkUnderline(t4))),this._register(s3.onHideLinkUnderline(t4=>this._handleHideLinkUnderline(t4)))}resize(t3,e3){;super.resize(t3,e3),this._state=void 0}reset(t3){this._clearCurrentLink()}_clearCurrentLink(){if(this._state){this._clearCells(this._state.x1,this._state.y1,this._state.cols-this._state.x1,1);const t3=this._state.y2-this._state.y1-1;t3>0&&this._clearCells(0,this._state.y1+1,this._state.cols,t3),this._clearCells(0,this._state.y2,this._state.x2,1),this._state=void 0}}_handleShowLinkUnderline(t3){if(t3.fg===r.INVERTED_DEFAULT_COLOR?this._ctx.fillStyle=this._themeService.colors.background.css:void 0!==t3.fg&&(0,s2.is256Color)(t3.fg)?this._ctx.fillStyle=this._themeService.colors.ansi[t3.fg].css:this._ctx.fillStyle=this._themeService.colors.foreground.css,t3.y1===t3.y2)this._fillBottomLineAtCells(t3.x1,t3.y1,t3.x2-t3.x1);else{this._fillBottomLineAtCells(t3.x1,t3.y1,t3.cols-t3.x1);for(let e3=t3.y1+1;e3{var t2=s;Object.defineProperty(t2,"__esModule",{value:true}),t2.WebglAddon=void 0;const e2=i(426),r=i(95),a=i(399),o=i(414);class n extends e2.Disposable{constructor(t3){if(r.isSafari&&(0,r.getSafariVersion)()<16){const t4={antialias:false,depth:false,preserveDrawingBuffer:true};if(!document.createElement("canvas").getContext("webgl2",t4))throw new Error("WebGL2 is only supported on Safari 16 and above")};super(),this._onChangeTextureAtlas=this._register(new o.Emitter),this.onChangeTextureAtlas=this._onChangeTextureAtlas.event,this._onAddTextureAtlasCanvas=this._register(new o.Emitter),this.onAddTextureAtlasCanvas=this._onAddTextureAtlasCanvas.event,this._onRemoveTextureAtlasCanvas=this._register(new o.Emitter),this.onRemoveTextureAtlasCanvas=this._onRemoveTextureAtlasCanvas.event,this._onContextLoss=this._register(new o.Emitter),this.onContextLoss=this._onContextLoss.event,this._customGlyphs=t3?.customGlyphs??true,this._preserveDrawingBuffer=t3?.preserveDrawingBuffer}activate(t3){const i2=t3._core;if(!t3.element)return void this._register(i2.onWillOpen(()=>this.activate(t3)));this._terminal=t3;const s2=i2.coreService,r2=i2.optionsService,n2=i2,L=n2._renderService,h=n2._characterJoinerService,T=n2._charSizeService,l=n2._coreBrowserService,d=n2._decorationService,c=n2._logService,_=n2._themeService;this._renderer=this._register(new a.WebglRenderer(t3,h,T,l,s2,d,c,r2,_,this._customGlyphs,this._preserveDrawingBuffer)),this._register(o.EventUtils.forward(this._renderer.onContextLoss,this._onContextLoss)),this._register(o.EventUtils.forward(this._renderer.onChangeTextureAtlas,this._onChangeTextureAtlas)),this._register(o.EventUtils.forward(this._renderer.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas)),this._register(o.EventUtils.forward(this._renderer.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas)),L.setRenderer(this._renderer),this._register((0,e2.toDisposable)(()=>{if(this._terminal._core._store._isDisposed)return;const e3=this._terminal._core._renderService;e3.setRenderer(this._terminal._core._createRenderer()),e3.handleResize(t3.cols,t3.rows)}))}get textureAtlas(){return this._renderer?.textureAtlas}clearTextureAtlas(){this._renderer?.clearTextureAtlas()}}t2.WebglAddon=n})(),s})()); -diff -ruN a/lib/addon-webgl.mjs b/lib/addon-webgl.mjs +diff --git a/lib/addon-webgl.mjs b/lib/addon-webgl.mjs --- a/lib/addon-webgl.mjs +++ b/lib/addon-webgl.mjs @@ -9,12 +9,7 @@ @@ -70,7 +70,7 @@ diff -ruN a/lib/addon-webgl.mjs b/lib/addon-webgl.mjs -}`,l0=8,Me=l0*Float32Array.BYTES_PER_ELEMENT,e1=20*l0,ne=class{constructor(){this.attributes=new Float32Array(e1),this.count=0}},p0=0,Lt=0,ht=0,dt=0,_t=0,ct=0,ut=0,ae=class extends W{constructor(t,r,s,a,o){super();this._terminal=t;this._gl=r;this._dimensions=s;this._themeService=a;this._logService=o;this._vertices=new ne;this._verticesCursor=new ne;let n=this._gl;this._program=g(ie(n,jt,Jt,this._logService)),this._register(M(()=>n.deleteProgram(this._program))),this._projectionLocation=g(n.getUniformLocation(this._program,"u_projection"));let L=this._vertexArrayObject=n.createVertexArray();this._register(M(()=>n.deleteVertexArray(L))),n.bindVertexArray(L);let T=new Float32Array([0,0,1,0,0,1,1,1]),h=n.createBuffer();this._register(M(()=>n.deleteBuffer(h))),n.bindBuffer(n.ARRAY_BUFFER,h),n.bufferData(n.ARRAY_BUFFER,T,n.STATIC_DRAW),n.enableVertexAttribArray(3),n.vertexAttribPointer(3,2,this._gl.FLOAT,!1,0,0);let d=new Uint8Array([0,1,2,3]),_=n.createBuffer();this._register(M(()=>n.deleteBuffer(_))),n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,_),n.bufferData(n.ELEMENT_ARRAY_BUFFER,d,n.STATIC_DRAW),this._attributesBuffer=g(n.createBuffer()),this._register(M(()=>n.deleteBuffer(this._attributesBuffer))),n.bindBuffer(n.ARRAY_BUFFER,this._attributesBuffer),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,!1,Me,0),n.vertexAttribDivisor(0,1),n.enableVertexAttribArray(1),n.vertexAttribPointer(1,2,n.FLOAT,!1,Me,2*Float32Array.BYTES_PER_ELEMENT),n.vertexAttribDivisor(1,1),n.enableVertexAttribArray(2),n.vertexAttribPointer(2,4,n.FLOAT,!1,Me,4*Float32Array.BYTES_PER_ELEMENT),n.vertexAttribDivisor(2,1),this._updateCachedColors(a.colors),this._register(this._themeService.onChangeColors(p=>{this._updateCachedColors(p),this._updateViewportRectangle()}))}renderBackgrounds(){this._renderVertices(this._vertices)}renderCursor(){this._renderVertices(this._verticesCursor)}_renderVertices(t){let r=this._gl;r.useProgram(this._program),r.bindVertexArray(this._vertexArrayObject),r.uniformMatrix4fv(this._projectionLocation,!1,te),r.bindBuffer(r.ARRAY_BUFFER,this._attributesBuffer),r.bufferData(r.ARRAY_BUFFER,t.attributes,r.DYNAMIC_DRAW),r.drawElementsInstanced(this._gl.TRIANGLE_STRIP,4,r.UNSIGNED_BYTE,0,t.count)}handleResize(){this._updateViewportRectangle()}setDimensions(t){this._dimensions=t}_updateCachedColors(t){this._bgFloat=this._colorToFloat32Array(t.background),this._cursorFloat=this._colorToFloat32Array(t.cursor)}_updateViewportRectangle(){this._addRectangleFloat(this._vertices.attributes,0,0,0,this._terminal.cols*this._dimensions.device.cell.width,this._terminal.rows*this._dimensions.device.cell.height,this._bgFloat)}updateBackgrounds(t){let r=this._terminal,s=this._vertices,a=1,o,n,L,T,h,d,_,p,c,u,C;for(o=0;o>24&255)/255,_t=(p0>>16&255)/255,ct=(p0>>8&255)/255,ut=1,this._addRectangle(t.attributes,r,Lt,ht,(n-o)*this._dimensions.device.cell.width,this._dimensions.device.cell.height,dt,_t,ct,ut)}_addRectangle(t,r,s,a,o,n,L,T,h,d){t[r]=s/this._dimensions.device.canvas.width,t[r+1]=a/this._dimensions.device.canvas.height,t[r+2]=o/this._dimensions.device.canvas.width,t[r+3]=n/this._dimensions.device.canvas.height,t[r+4]=L,t[r+5]=T,t[r+6]=h,t[r+7]=d}_addRectangleFloat(t,r,s,a,o,n,L){t[r]=s/this._dimensions.device.canvas.width,t[r+1]=a/this._dimensions.device.canvas.height,t[r+2]=o/this._dimensions.device.canvas.width,t[r+3]=n/this._dimensions.device.canvas.height,t[r+4]=L[0],t[r+5]=L[1],t[r+6]=L[2],t[r+7]=L[3]}_colorToFloat32Array(t){return new Float32Array([(t.rgba>>24&255)/255,(t.rgba>>16&255)/255,(t.rgba>>8&255)/255,(t.rgba&255)/255])}};var oe=class extends W{constructor(t,r,s,a,o,n,L,T){super();this._container=r;this._alpha=o;this._coreBrowserService=n;this._optionsService=L;this._themeService=T;this._deviceCharWidth=0;this._deviceCharHeight=0;this._deviceCellWidth=0;this._deviceCellHeight=0;this._deviceCharLeft=0;this._deviceCharTop=0;this._canvas=this._coreBrowserService.mainDocument.createElement("canvas"),this._canvas.classList.add(`xterm-${s}-layer`),this._canvas.style.zIndex=a.toString(),this._initCanvas(),this._container.appendChild(this._canvas),this._register(this._themeService.onChangeColors(h=>{this._refreshCharAtlas(t,h),this.reset(t)})),this._register(M(()=>{this._canvas.remove()}))}_initCanvas(){this._ctx=g(this._canvas.getContext("2d",{alpha:this._alpha})),this._alpha||this._clearAll()}handleBlur(t){}handleFocus(t){}handleCursorMove(t){}handleGridChanged(t,r,s){}handleSelectionChanged(t,r,s,a=!1){}_setTransparency(t,r){if(r===this._alpha)return;let s=this._canvas;this._alpha=r,this._canvas=this._canvas.cloneNode(),this._initCanvas(),this._container.replaceChild(this._canvas,s),this._refreshCharAtlas(t,this._themeService.colors),this.handleGridChanged(t,0,t.rows-1)}_refreshCharAtlas(t,r){this._deviceCharWidth<=0&&this._deviceCharHeight<=0||(this._charAtlas=Y0(t,this._optionsService.rawOptions,r,this._deviceCellWidth,this._deviceCellHeight,this._deviceCharWidth,this._deviceCharHeight,this._coreBrowserService.dpr,2048),this._charAtlas.warmUp())}resize(t,r){this._deviceCellWidth=r.device.cell.width,this._deviceCellHeight=r.device.cell.height,this._deviceCharWidth=r.device.char.width,this._deviceCharHeight=r.device.char.height,this._deviceCharLeft=r.device.char.left,this._deviceCharTop=r.device.char.top,this._canvas.width=r.device.canvas.width,this._canvas.height=r.device.canvas.height,this._canvas.style.width=`${r.css.canvas.width}px`,this._canvas.style.height=`${r.css.canvas.height}px`,this._alpha||this._clearAll(),this._refreshCharAtlas(t,this._themeService.colors)}_fillBottomLineAtCells(t,r,s=1){this._ctx.fillRect(t*this._deviceCellWidth,(r+1)*this._deviceCellHeight-this._coreBrowserService.dpr-1,s*this._deviceCellWidth,this._coreBrowserService.dpr)}_clearAll(){this._alpha?this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(0,0,this._canvas.width,this._canvas.height))}_clearCells(t,r,s,a){this._alpha?this._ctx.clearRect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,a*this._deviceCellHeight):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,a*this._deviceCellHeight))}_fillCharTrueColor(t,r,s,a){this._ctx.font=this._getFont(t,!1,!1),this._ctx.textBaseline=K0,this._clipCell(s,a,r.getWidth()),this._ctx.fillText(r.getChars(),s*this._deviceCellWidth+this._deviceCharLeft,a*this._deviceCellHeight+this._deviceCharTop+this._deviceCharHeight)}_clipCell(t,r,s){this._ctx.beginPath(),this._ctx.rect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,this._deviceCellHeight),this._ctx.clip()}_getFont(t,r,s){let a=r?t.options.fontWeightBold:t.options.fontWeight;return`${s?"italic":""} ${a} ${t.options.fontSize*this._coreBrowserService.dpr}px ${t.options.fontFamily}`}};var Te=class extends oe{constructor(e,t,r,s,a,o,n){super(r,e,"link",t,!0,a,o,n),this._register(s.onShowLinkUnderline(L=>this._handleShowLinkUnderline(L))),this._register(s.onHideLinkUnderline(L=>this._handleHideLinkUnderline(L)))}resize(e,t){super.resize(e,t),this._state=void 0}reset(e){this._clearCurrentLink()}_clearCurrentLink(){if(this._state){this._clearCells(this._state.x1,this._state.y1,this._state.cols-this._state.x1,1);let e=this._state.y2-this._state.y1-1;e>0&&this._clearCells(0,this._state.y1+1,this._state.cols,e),this._clearCells(0,this._state.y2,this._state.x2,1),this._state=void 0}}_handleShowLinkUnderline(e){if(e.fg===257?this._ctx.fillStyle=this._themeService.colors.background.css:e.fg!==void 0&&st(e.fg)?this._ctx.fillStyle=this._themeService.colors.ansi[e.fg].css:this._ctx.fillStyle=this._themeService.colors.foreground.css,e.y1===e.y2)this._fillBottomLineAtCells(e.x1,e.y1,e.x2-e.x1);else{this._fillBottomLineAtCells(e.x1,e.y1,e.cols-e.x1);for(let t=e.y1+1;tthis._handleColorChange())),this._cellColorResolver=new G0(this._terminal,this._optionsService,this._model.selection,this._decorationService,this._coreBrowserService,this._themeService),this._core=this._terminal._core,this._renderLayers=[new Te(this._core.screenElement,2,this._terminal,this._core.linkifier,this._coreBrowserService,T,this._themeService)],this.dimensions=Ue(),this._devicePixelRatio=this._coreBrowserService.dpr,this._updateDimensions(),this._updateCursorBlink(),this._register(T.onOptionChange(()=>this._handleOptionsChanged())),this._textBlinkStateManager=this._register(new J0(()=>this._requestRedrawViewport(),this._coreBrowserService,this._optionsService)),this._resetBlinkingRowState(),this._deviceMaxTextureSize=this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE),this._register(le(this._canvas,"webglcontextlost",c=>{this._logService.debug("webglcontextlost event received"),c.preventDefault(),this._contextRestorationTimeout=setTimeout(()=>{this._contextRestorationTimeout=void 0,this._logService.warn("webgl context not restored; firing onContextLoss"),this._onContextLoss.fire(c)},3e3)})),this._register(le(this._canvas,"webglcontextrestored",c=>{this._logService.warn("webglcontextrestored event received"),clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0,be(this._terminal),this._initializeWebGLState(),this._requestRedrawViewport()})),this._observerDisposable.value=ve(this._canvas,this._coreBrowserService.window,(c,u)=>this._setCanvasDevicePixelDimensions(c,u)),this._register(this._coreBrowserService.onWindowChange(c=>{this._observerDisposable.value=ve(this._canvas,c,(u,C)=>this._setCanvasDevicePixelDimensions(u,C))})),this._register(le(this._coreBrowserService.mainDocument,"mousedown",()=>this._cursorBlinkStateManager.value?.restartBlinkAnimation())),this._core.screenElement.appendChild(this._canvas),[this._rectangleRenderer.value,this._glyphRenderer.value]=this._initializeWebGLState(),this._isAttached=this._core.screenElement.isConnected,this._register(M(()=>{clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0;for(let c of this._renderLayers)c.dispose();this._canvas.parentElement?.removeChild(this._canvas),be(this._terminal)}))}get textureAtlas(){return this._charAtlas?.pages[0].canvas}_handleColorChange(){this._refreshCharAtlas(),this._clearModel(!0)}handleDevicePixelRatioChange(){this._devicePixelRatio!==this._coreBrowserService.dpr&&(this._devicePixelRatio=this._coreBrowserService.dpr,this.handleResize(this._terminal.cols,this._terminal.rows))}handleResize(t,r){this._updateDimensions(),this._model.resize(this._terminal.cols,this._terminal.rows),this._resetBlinkingRowState();for(let s of this._renderLayers)s.resize(this._terminal,this.dimensions);this._canvas.width=this.dimensions.device.canvas.width,this._canvas.height=this.dimensions.device.canvas.height,this._canvas.style.width=`${this.dimensions.css.canvas.width}px`,this._canvas.style.height=`${this.dimensions.css.canvas.height}px`,this._core.screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._core.screenElement.style.height=`${this.dimensions.css.canvas.height}px`,this._rectangleRenderer.value?.setDimensions(this.dimensions),this._rectangleRenderer.value?.handleResize(),this._glyphRenderer.value?.setDimensions(this.dimensions),this._glyphRenderer.value?.handleResize(),this._refreshCharAtlas(),this._clearModel(!1),this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:!0})}handleCharSizeChanged(){this.handleResize(this._terminal.cols,this._terminal.rows)}handleBlur(){for(let t of this._renderLayers)t.handleBlur(this._terminal);this._cursorBlinkStateManager.value?.pause(),this._requestRedrawViewport()}handleFocus(){for(let t of this._renderLayers)t.handleFocus(this._terminal);this._cursorBlinkStateManager.value?.resume(),this._requestRedrawViewport()}handleViewportVisibilityChange(t){this._textBlinkStateManager.setViewportVisible(t)}handleSelectionChanged(t,r,s){for(let a of this._renderLayers)a.handleSelectionChanged(this._terminal,t,r,s);this._model.selection.update(this._core,t,r,s),this._requestRedrawViewport()}handleCursorMove(){for(let t of this._renderLayers)t.handleCursorMove(this._terminal);this._cursorBlinkStateManager.value?.restartBlinkAnimation()}_handleOptionsChanged(){this._updateDimensions(),this._refreshCharAtlas(),this._updateCursorBlink()}_initializeWebGLState(){return this._rectangleRenderer.value=new ae(this._terminal,this._gl,this.dimensions,this._themeService,this._logService),this._glyphRenderer.value=new re(this._terminal,this._gl,this.dimensions,this._optionsService,this._logService),this.handleCharSizeChanged(),[this._rectangleRenderer.value,this._glyphRenderer.value]}_refreshCharAtlas(){if(this.dimensions.device.char.width<=0&&this.dimensions.device.char.height<=0){this._isAttached=!1;return}let t=Y0(this._terminal,this._optionsService.rawOptions,this._themeService.colors,this.dimensions.device.cell.width,this.dimensions.device.cell.height,this.dimensions.device.char.width,this.dimensions.device.char.height,this._coreBrowserService.dpr,this._deviceMaxTextureSize,this._customGlyphs);this._charAtlas!==t&&(this._onChangeTextureAtlas.fire(t.pages[0].canvas),this._charAtlasDisposable.value=De(c0.forward(t.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas),c0.forward(t.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas))),this._charAtlas=t,this._charAtlas.warmUp(),this._glyphRenderer.value?.setAtlas(this._charAtlas)}_clearModel(t){this._model.clear(),t&&this._glyphRenderer.value?.clear()}clearTextureAtlas(){this._charAtlas?.clearTexture(),this._clearModel(!0),this._requestRedrawViewport()}clear(){this._clearModel(!0);for(let t of this._renderLayers)t.reset(this._terminal);this._resetBlinkingRowState(),this._textBlinkStateManager.setNeedsBlinkInViewport(!1),this._cursorBlinkStateManager.value?.restartBlinkAnimation(),this._updateCursorBlink()}renderRows(t,r){if(!this._isAttached)if(this._core.screenElement?.isConnected&&this._charSizeService.width&&this._charSizeService.height)this._updateDimensions(),this._refreshCharAtlas(),this._isAttached=!0;else return;for(let o of this._renderLayers)o.handleGridChanged(this._terminal,t,r);if(!this._glyphRenderer.value||!this._rectangleRenderer.value)return;this._glyphRenderer.value.beginFrame()?(this._clearModel(!0),this._updateModel(0,this._terminal.rows-1)):this._updateModel(t,r);let s=!1,a=0;for(;this._charAtlas&&this._glyphRenderer.value.beginFrame()&&a++<32;)s=!0,this._clearModel(!0),this._updateModel(0,this._terminal.rows-1);s&&this._glyphRenderer.value.invalidateAtlasTextures(),this._rectangleRenderer.value.renderBackgrounds(),this._glyphRenderer.value.render(this._model),(!this._cursorBlinkStateManager.value||this._cursorBlinkStateManager.value.isCursorVisible)&&this._rectangleRenderer.value.renderCursor()}_updateCursorBlink(){this._coreService.decPrivateModes.cursorBlink??this._terminal.options.cursorBlink?this._cursorBlinkStateManager.value=new q0(()=>{this._requestRedrawCursor()},this._coreBrowserService):this._cursorBlinkStateManager.clear(),this._requestRedrawCursor()}_updateModel(t,r){let s=this._core,a=this._workCell,o,n,L,T,h,d,_,p,c,u,C,Q,m,R,F,E,y;t=pt(t,s.rows-1,0),r=pt(r,s.rows-1,0);let Y=this._coreService.decPrivateModes.cursorStyle??s.options.cursorStyle??"block",X=this._terminal.buffer.active.baseY+this._terminal.buffer.active.cursorY,A0=X-s.buffer.ydisp,t0=Math.min(this._terminal.buffer.active.cursorX,s.cols-1),L0=-1,A=this._coreService.isCursorInitialized&&!this._coreService.isCursorHidden&&(!this._cursorBlinkStateManager.value||this._cursorBlinkStateManager.value.isCursorVisible);this._model.cursor=void 0;let n0=!1;for(n=t;n<=r;n++){L=n+s.buffer.ydisp;let a0=s.buffer.lines.get(L);if(!a0){for(this._model.lineLengths[n]=0,E=0;E=_,c=E,h.length>0&&E===h[0][0]&&p){u=h.shift();let q=this._model.selection.isCellSelected(this._terminal,u[0],L);for(F=u[0]+1;F=u[1],p?(d=!0,a=new ge(a,T.translateToString(!0,u[0],u[1]),u[1]-u[0]),c=u[1]-1):_=u[1]}if(Q=a.getChars(),m=a.getCode(),F=(n*s.cols+E)*4,!$&&a.isBlink()&&($=!0),this._cellColorResolver.resolve(a,E,L,this.dimensions.device.cell.width,this.dimensions.device.cell.height),A&&L===X&&(E===t0&&(this._model.cursor={x:t0,y:A0,width:a.getWidth(),style:this._coreBrowserService.isFocused?Y:s.options.cursorInactiveStyle,cursorWidth:s.options.cursorWidth,dpr:this._devicePixelRatio},L0=t0+a.getWidth()-1),E>=t0&&E<=L0&&(this._coreBrowserService.isFocused&&Y==="block"||this._coreBrowserService.isFocused===!1&&s.options.cursorInactiveStyle==="block")&&(this._cellColorResolver.result.fg=50331648|this._themeService.colors.cursorAccent.rgba>>8&16777215,this._cellColorResolver.result.bg=50331648|this._themeService.colors.cursor.rgba>>8&16777215)),this._textBlinkStateManager.isEnabled&&!this._textBlinkStateManager.isBlinkOn&&a.isBlink()&&(this._cellColorResolver.result.fg|=1073741824),m!==0&&(this._model.lineLengths[n]=E+1),!(this._model.cells[F]===m&&this._model.cells[F+1]===this._cellColorResolver.result.bg&&this._model.cells[F+2]===this._cellColorResolver.result.fg&&this._model.cells[F+3]===this._cellColorResolver.result.ext)&&(n0=!0,Q.length>1&&(m|=lt),this._model.cells[F]=m,this._model.cells[F+1]=this._cellColorResolver.result.bg,this._model.cells[F+2]=this._cellColorResolver.result.fg,this._model.cells[F+3]=this._cellColorResolver.result.ext,R=a.getWidth(),this._glyphRenderer.value.updateCell(E,n,m,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext,Q,R,o),d)){for(a=this._workCell,E++;E<=c;E++)y=(n*s.cols+E)*4,this._nullModelCell(E,n,y,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext);E--}}this._setRowBlinkState(n,$)}n0&&this._rectangleRenderer.value.updateBackgrounds(this._model),this._rectangleRenderer.value.updateCursor(this._model),this._updateTextBlinkState()}_nullModelCell(t,r,s,a,o,n){this._glyphRenderer.value.updateCell(t,r,0,a,o,n,"",0,0),this._model.cells[s]=0,this._model.cells[s+1]=a,this._model.cells[s+2]=o,this._model.cells[s+3]=n}_resetBlinkingRowState(){this._rowHasBlinkingCells=new Array(this._terminal.rows).fill(!1),this._rowHasBlinkingCellsCount=0}_setRowBlinkState(t,r){this._rowHasBlinkingCells[t]!==r&&(this._rowHasBlinkingCells[t]=r,this._rowHasBlinkingCellsCount+=r?1:-1)}_updateTextBlinkState(){this._textBlinkStateManager.setNeedsBlinkInViewport(this._rowHasBlinkingCellsCount>0)}_updateDimensions(){!this._charSizeService.width||!this._charSizeService.height||(this.dimensions.device.char.width=Math.floor(this._charSizeService.width*this._devicePixelRatio),this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*this._devicePixelRatio),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.top=this._optionsService.rawOptions.lineHeight===1?0:Math.round((this.dimensions.device.cell.height-this.dimensions.device.char.height)/2),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.char.left=Math.floor(this._optionsService.rawOptions.letterSpacing/2),this.dimensions.device.canvas.height=this._terminal.rows*this.dimensions.device.cell.height,this.dimensions.device.canvas.width=this._terminal.cols*this.dimensions.device.cell.width,this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/this._devicePixelRatio),this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/this._devicePixelRatio),this.dimensions.css.cell.height=this.dimensions.device.cell.height/this._devicePixelRatio,this.dimensions.css.cell.width=this.dimensions.device.cell.width/this._devicePixelRatio)}_setCanvasDevicePixelDimensions(t,r){this._canvas.width===t&&this._canvas.height===r||(this._canvas.width=t,this._canvas.height=r,this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:!0}))}_requestRedrawViewport(){this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1})}_requestRedrawCursor(){let t=this._terminal.buffer.active.cursorY;this._onRequestRedraw.fire({start:t,end:t})}},ge=class extends s0{constructor(t,r,s){super();this.content=0;this.combinedData="";this.fg=t.fg,this.bg=t.bg,this.combinedData=r,this._width=s}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(t){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}};function pt(i,e,t=0){return Math.max(Math.min(i,e),t)}var Ct=class extends W{constructor(t){if(ue&&He()<16){let r={antialias:!1,depth:!1,preserveDrawingBuffer:!0};if(!document.createElement("canvas").getContext("webgl2",r))throw new Error("WebGL2 is only supported on Safari 16 and above")}super();this._onChangeTextureAtlas=this._register(new U);this.onChangeTextureAtlas=this._onChangeTextureAtlas.event;this._onAddTextureAtlasCanvas=this._register(new U);this.onAddTextureAtlasCanvas=this._onAddTextureAtlasCanvas.event;this._onRemoveTextureAtlasCanvas=this._register(new U);this.onRemoveTextureAtlasCanvas=this._onRemoveTextureAtlasCanvas.event;this._onContextLoss=this._register(new U);this.onContextLoss=this._onContextLoss.event;this._customGlyphs=t?.customGlyphs??!0,this._preserveDrawingBuffer=t?.preserveDrawingBuffer}activate(t){let r=t._core;if(!t.element){this._register(r.onWillOpen(()=>this.activate(t)));return}this._terminal=t;let s=r.coreService,a=r.optionsService,o=r,n=o._renderService,L=o._characterJoinerService,T=o._charSizeService,h=o._coreBrowserService,d=o._decorationService,_=o._logService,p=o._themeService;this._renderer=this._register(new Le(t,L,T,h,s,d,_,a,p,this._customGlyphs,this._preserveDrawingBuffer)),this._register(c0.forward(this._renderer.onContextLoss,this._onContextLoss)),this._register(c0.forward(this._renderer.onChangeTextureAtlas,this._onChangeTextureAtlas)),this._register(c0.forward(this._renderer.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas)),this._register(c0.forward(this._renderer.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas)),n.setRenderer(this._renderer),this._register(M(()=>{if(this._terminal._core._store._isDisposed)return;let c=this._terminal._core._renderService;c.setRenderer(this._terminal._core._createRenderer()),c.handleResize(t.cols,t.rows)}))}get textureAtlas(){return this._renderer?.textureAtlas}clearTextureAtlas(){this._renderer?.clearTextureAtlas()}};export{Ct as WebglAddon}; -//# sourceMappingURL=addon-webgl.mjs.map +}`,l0=8,Me=l0*Float32Array.BYTES_PER_ELEMENT,e1=20*l0,ne=class{constructor(){;this.attributes=new Float32Array(e1),this.count=0}},p0=0,Lt=0,ht=0,dt=0,_t=0,ct=0,ut=0,ae=class extends W{constructor(t,r,s,a,o){super();this._terminal=t;this._gl=r;this._dimensions=s;this._themeService=a;this._logService=o;this._vertices=new ne;this._verticesCursor=new ne;let n=this._gl;this._program=g(ie(n,jt,Jt,this._logService)),this._register(M(()=>n.deleteProgram(this._program))),this._projectionLocation=g(n.getUniformLocation(this._program,"u_projection"));let L=this._vertexArrayObject=n.createVertexArray();this._register(M(()=>n.deleteVertexArray(L))),n.bindVertexArray(L);let T=new Float32Array([0,0,1,0,0,1,1,1]),h=n.createBuffer();this._register(M(()=>n.deleteBuffer(h))),n.bindBuffer(n.ARRAY_BUFFER,h),n.bufferData(n.ARRAY_BUFFER,T,n.STATIC_DRAW),n.enableVertexAttribArray(3),n.vertexAttribPointer(3,2,this._gl.FLOAT,false,0,0);let d=new Uint8Array([0,1,2,3]),_=n.createBuffer();this._register(M(()=>n.deleteBuffer(_))),n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,_),n.bufferData(n.ELEMENT_ARRAY_BUFFER,d,n.STATIC_DRAW),this._attributesBuffer=g(n.createBuffer()),this._register(M(()=>n.deleteBuffer(this._attributesBuffer))),n.bindBuffer(n.ARRAY_BUFFER,this._attributesBuffer),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,false,Me,0),n.vertexAttribDivisor(0,1),n.enableVertexAttribArray(1),n.vertexAttribPointer(1,2,n.FLOAT,false,Me,2*Float32Array.BYTES_PER_ELEMENT),n.vertexAttribDivisor(1,1),n.enableVertexAttribArray(2),n.vertexAttribPointer(2,4,n.FLOAT,false,Me,4*Float32Array.BYTES_PER_ELEMENT),n.vertexAttribDivisor(2,1),this._updateCachedColors(a.colors),this._register(this._themeService.onChangeColors(p=>{;this._updateCachedColors(p),this._updateViewportRectangle()}))}renderBackgrounds(){this._renderVertices(this._vertices)}renderCursor(){this._renderVertices(this._verticesCursor)}_renderVertices(t){let r=this._gl;r.useProgram(this._program),r.bindVertexArray(this._vertexArrayObject),r.uniformMatrix4fv(this._projectionLocation,false,te),r.bindBuffer(r.ARRAY_BUFFER,this._attributesBuffer),r.bufferData(r.ARRAY_BUFFER,t.attributes,r.DYNAMIC_DRAW),r.drawElementsInstanced(this._gl.TRIANGLE_STRIP,4,r.UNSIGNED_BYTE,0,t.count)}handleResize(){this._updateViewportRectangle()}setDimensions(t){this._dimensions=t}_updateCachedColors(t){;this._bgFloat=this._colorToFloat32Array(t.background),this._cursorFloat=this._colorToFloat32Array(t.cursor)}_updateViewportRectangle(){this._addRectangleFloat(this._vertices.attributes,0,0,0,this._terminal.cols*this._dimensions.device.cell.width,this._terminal.rows*this._dimensions.device.cell.height,this._bgFloat)}updateBackgrounds(t){let r=this._terminal,s=this._vertices,a=1,o,n,L,T,h,d,_,p,c,u,C;for(o=0;o>24&255)/255,_t=(p0>>16&255)/255,ct=(p0>>8&255)/255,ut=1,this._addRectangle(t.attributes,r,Lt,ht,(n-o)*this._dimensions.device.cell.width,this._dimensions.device.cell.height,dt,_t,ct,ut)}_addRectangle(t,r,s,a,o,n,L,T,h,d){;t[r]=s/this._dimensions.device.canvas.width,t[r+1]=a/this._dimensions.device.canvas.height,t[r+2]=o/this._dimensions.device.canvas.width,t[r+3]=n/this._dimensions.device.canvas.height,t[r+4]=L,t[r+5]=T,t[r+6]=h,t[r+7]=d}_addRectangleFloat(t,r,s,a,o,n,L){;t[r]=s/this._dimensions.device.canvas.width,t[r+1]=a/this._dimensions.device.canvas.height,t[r+2]=o/this._dimensions.device.canvas.width,t[r+3]=n/this._dimensions.device.canvas.height,t[r+4]=L[0],t[r+5]=L[1],t[r+6]=L[2],t[r+7]=L[3]}_colorToFloat32Array(t){return new Float32Array([(t.rgba>>24&255)/255,(t.rgba>>16&255)/255,(t.rgba>>8&255)/255,(t.rgba&255)/255])}};var oe=class extends W{constructor(t,r,s,a,o,n,L,T){super();this._container=r;this._alpha=o;this._coreBrowserService=n;this._optionsService=L;this._themeService=T;this._deviceCharWidth=0;this._deviceCharHeight=0;this._deviceCellWidth=0;this._deviceCellHeight=0;this._deviceCharLeft=0;this._deviceCharTop=0;this._canvas=this._coreBrowserService.mainDocument.createElement("canvas"),this._canvas.classList.add(`xterm-${s}-layer`),this._canvas.style.zIndex=a.toString(),this._initCanvas(),this._container.appendChild(this._canvas),this._register(this._themeService.onChangeColors(h=>{;this._refreshCharAtlas(t,h),this.reset(t)})),this._register(M(()=>{this._canvas.remove()}))}_initCanvas(){;this._ctx=g(this._canvas.getContext("2d",{alpha:this._alpha})),this._alpha||this._clearAll()}handleBlur(t){}handleFocus(t){}handleCursorMove(t){}handleGridChanged(t,r,s){}handleSelectionChanged(t,r,s,a=false){}_setTransparency(t,r){if(r===this._alpha)return;let s=this._canvas;this._alpha=r,this._canvas=this._canvas.cloneNode(),this._initCanvas(),this._container.replaceChild(this._canvas,s),this._refreshCharAtlas(t,this._themeService.colors),this.handleGridChanged(t,0,t.rows-1)}_refreshCharAtlas(t,r){;this._deviceCharWidth<=0&&this._deviceCharHeight<=0||(this._charAtlas=Y0(t,this._optionsService.rawOptions,r,this._deviceCellWidth,this._deviceCellHeight,this._deviceCharWidth,this._deviceCharHeight,this._coreBrowserService.dpr,2048),this._charAtlas.warmUp())}resize(t,r){;this._deviceCellWidth=r.device.cell.width,this._deviceCellHeight=r.device.cell.height,this._deviceCharWidth=r.device.char.width,this._deviceCharHeight=r.device.char.height,this._deviceCharLeft=r.device.char.left,this._deviceCharTop=r.device.char.top,this._canvas.width=r.device.canvas.width,this._canvas.height=r.device.canvas.height,this._canvas.style.width=`${r.css.canvas.width}px`,this._canvas.style.height=`${r.css.canvas.height}px`,this._alpha||this._clearAll(),this._refreshCharAtlas(t,this._themeService.colors)}_fillBottomLineAtCells(t,r,s=1){this._ctx.fillRect(t*this._deviceCellWidth,(r+1)*this._deviceCellHeight-this._coreBrowserService.dpr-1,s*this._deviceCellWidth,this._coreBrowserService.dpr)}_clearAll(){this._alpha?this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(0,0,this._canvas.width,this._canvas.height))}_clearCells(t,r,s,a){this._alpha?this._ctx.clearRect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,a*this._deviceCellHeight):(this._ctx.fillStyle=this._themeService.colors.background.css,this._ctx.fillRect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,a*this._deviceCellHeight))}_fillCharTrueColor(t,r,s,a){;this._ctx.font=this._getFont(t,false,false),this._ctx.textBaseline=K0,this._clipCell(s,a,r.getWidth()),this._ctx.fillText(r.getChars(),s*this._deviceCellWidth+this._deviceCharLeft,a*this._deviceCellHeight+this._deviceCharTop+this._deviceCharHeight)}_clipCell(t,r,s){;this._ctx.beginPath(),this._ctx.rect(t*this._deviceCellWidth,r*this._deviceCellHeight,s*this._deviceCellWidth,this._deviceCellHeight),this._ctx.clip()}_getFont(t,r,s){let a=r?t.options.fontWeightBold:t.options.fontWeight;return`${s?"italic":""} ${a} ${t.options.fontSize*this._coreBrowserService.dpr}px ${t.options.fontFamily}`}};var Te=class extends oe{constructor(e,t,r,s,a,o,n){;super(r,e,"link",t,true,a,o,n),this._register(s.onShowLinkUnderline(L=>this._handleShowLinkUnderline(L))),this._register(s.onHideLinkUnderline(L=>this._handleHideLinkUnderline(L)))}resize(e,t){;super.resize(e,t),this._state=void 0}reset(e){this._clearCurrentLink()}_clearCurrentLink(){if(this._state){this._clearCells(this._state.x1,this._state.y1,this._state.cols-this._state.x1,1);let e=this._state.y2-this._state.y1-1;e>0&&this._clearCells(0,this._state.y1+1,this._state.cols,e),this._clearCells(0,this._state.y2,this._state.x2,1),this._state=void 0}}_handleShowLinkUnderline(e){if(e.fg===257?this._ctx.fillStyle=this._themeService.colors.background.css:e.fg!==void 0&&st(e.fg)?this._ctx.fillStyle=this._themeService.colors.ansi[e.fg].css:this._ctx.fillStyle=this._themeService.colors.foreground.css,e.y1===e.y2)this._fillBottomLineAtCells(e.x1,e.y1,e.x2-e.x1);else{this._fillBottomLineAtCells(e.x1,e.y1,e.cols-e.x1);for(let t=e.y1+1;tthis._handleColorChange())),this._cellColorResolver=new G0(this._terminal,this._optionsService,this._model.selection,this._decorationService,this._coreBrowserService,this._themeService),this._core=this._terminal._core,this._renderLayers=[new Te(this._core.screenElement,2,this._terminal,this._core.linkifier,this._coreBrowserService,T,this._themeService)],this.dimensions=Ue(),this._devicePixelRatio=this._coreBrowserService.dpr,this._updateDimensions(),this._updateCursorBlink(),this._register(T.onOptionChange(()=>this._handleOptionsChanged())),this._textBlinkStateManager=this._register(new J0(()=>this._requestRedrawViewport(),this._coreBrowserService,this._optionsService)),this._resetBlinkingRowState(),this._deviceMaxTextureSize=this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE),this._register(le(this._canvas,"webglcontextlost",c=>{;this._logService.debug("webglcontextlost event received"),c.preventDefault(),this._contextRestorationTimeout=setTimeout(()=>{;this._contextRestorationTimeout=void 0,this._logService.warn("webgl context not restored; firing onContextLoss"),this._onContextLoss.fire(c)},3e3)})),this._register(le(this._canvas,"webglcontextrestored",c=>{;this._logService.warn("webglcontextrestored event received"),clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0,be(this._terminal),this._initializeWebGLState(),this._requestRedrawViewport()})),this._observerDisposable.value=ve(this._canvas,this._coreBrowserService.window,(c,u)=>this._setCanvasDevicePixelDimensions(c,u)),this._register(this._coreBrowserService.onWindowChange(c=>{this._observerDisposable.value=ve(this._canvas,c,(u,C)=>this._setCanvasDevicePixelDimensions(u,C))})),this._register(le(this._coreBrowserService.mainDocument,"mousedown",()=>this._cursorBlinkStateManager.value?.restartBlinkAnimation())),this._core.screenElement.appendChild(this._canvas),[this._rectangleRenderer.value,this._glyphRenderer.value]=this._initializeWebGLState(),this._isAttached=this._core.screenElement.isConnected,this._register(M(()=>{;clearTimeout(this._contextRestorationTimeout),this._contextRestorationTimeout=void 0;for(let c of this._renderLayers)c.dispose();this._canvas.parentElement?.removeChild(this._canvas),be(this._terminal)}))}get textureAtlas(){return this._charAtlas?.pages[0].canvas}_handleColorChange(){;this._refreshCharAtlas(),this._clearModel(true)}handleDevicePixelRatioChange(){this._devicePixelRatio!==this._coreBrowserService.dpr&&(this._devicePixelRatio=this._coreBrowserService.dpr,this.handleResize(this._terminal.cols,this._terminal.rows))}handleResize(t,r){;this._updateDimensions(),this._model.resize(this._terminal.cols,this._terminal.rows),this._resetBlinkingRowState();for(let s of this._renderLayers)s.resize(this._terminal,this.dimensions);this._canvas.width=this.dimensions.device.canvas.width,this._canvas.height=this.dimensions.device.canvas.height,this._canvas.style.width=`${this.dimensions.css.canvas.width}px`,this._canvas.style.height=`${this.dimensions.css.canvas.height}px`,this._core.screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._core.screenElement.style.height=`${this.dimensions.css.canvas.height}px`,this._rectangleRenderer.value?.setDimensions(this.dimensions),this._rectangleRenderer.value?.handleResize(),this._glyphRenderer.value?.setDimensions(this.dimensions),this._glyphRenderer.value?.handleResize(),this._refreshCharAtlas(),this._clearModel(false),this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:true})}handleCharSizeChanged(){this.handleResize(this._terminal.cols,this._terminal.rows)}handleBlur(){for(let t of this._renderLayers)t.handleBlur(this._terminal);this._cursorBlinkStateManager.value?.pause(),this._requestRedrawViewport()}handleFocus(){for(let t of this._renderLayers)t.handleFocus(this._terminal);this._cursorBlinkStateManager.value?.resume(),this._requestRedrawViewport()}handleViewportVisibilityChange(t){this._textBlinkStateManager.setViewportVisible(t)}handleSelectionChanged(t,r,s){for(let a of this._renderLayers)a.handleSelectionChanged(this._terminal,t,r,s);this._model.selection.update(this._core,t,r,s),this._requestRedrawViewport()}handleCursorMove(){for(let t of this._renderLayers)t.handleCursorMove(this._terminal);this._cursorBlinkStateManager.value?.restartBlinkAnimation()}_handleOptionsChanged(){;this._updateDimensions(),this._refreshCharAtlas(),this._updateCursorBlink()}_initializeWebGLState(){return this._rectangleRenderer.value=new ae(this._terminal,this._gl,this.dimensions,this._themeService,this._logService),this._glyphRenderer.value=new re(this._terminal,this._gl,this.dimensions,this._optionsService,this._logService),this.handleCharSizeChanged(),[this._rectangleRenderer.value,this._glyphRenderer.value]}_refreshCharAtlas(){if(this.dimensions.device.char.width<=0&&this.dimensions.device.char.height<=0){this._isAttached=false;return}let t=Y0(this._terminal,this._optionsService.rawOptions,this._themeService.colors,this.dimensions.device.cell.width,this.dimensions.device.cell.height,this.dimensions.device.char.width,this.dimensions.device.char.height,this._coreBrowserService.dpr,this._deviceMaxTextureSize,this._customGlyphs);this._charAtlas!==t&&(this._onChangeTextureAtlas.fire(t.pages[0].canvas),this._charAtlasDisposable.value=De(c0.forward(t.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas),c0.forward(t.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas))),this._charAtlas=t,this._charAtlas.warmUp(),this._glyphRenderer.value?.setAtlas(this._charAtlas)}_clearModel(t){;this._model.clear(),t&&this._glyphRenderer.value?.clear()}clearTextureAtlas(){;this._charAtlas?.clearTexture(),this._clearModel(true),this._requestRedrawViewport()}clear(){this._clearModel(true);for(let t of this._renderLayers)t.reset(this._terminal);this._resetBlinkingRowState(),this._textBlinkStateManager.setNeedsBlinkInViewport(false),this._cursorBlinkStateManager.value?.restartBlinkAnimation(),this._updateCursorBlink()}renderRows(t,r){if(!this._isAttached)if(this._core.screenElement?.isConnected&&this._charSizeService.width&&this._charSizeService.height)this._updateDimensions(),this._refreshCharAtlas(),this._isAttached=true;else return;for(let o of this._renderLayers)o.handleGridChanged(this._terminal,t,r);if(!this._glyphRenderer.value||!this._rectangleRenderer.value)return;this._glyphRenderer.value.beginFrame()?(this._clearModel(true),this._updateModel(0,this._terminal.rows-1)):this._updateModel(t,r);let s=false,a=0;for(;this._charAtlas&&a++<32&&this._glyphRenderer.value.beginFrame();)s=true,this._clearModel(true),this._updateModel(0,this._terminal.rows-1);s&&this._glyphRenderer.value.invalidateAtlasTextures(),this._rectangleRenderer.value.renderBackgrounds(),this._glyphRenderer.value.render(this._model),(!this._cursorBlinkStateManager.value||this._cursorBlinkStateManager.value.isCursorVisible)&&this._rectangleRenderer.value.renderCursor()}_updateCursorBlink(){;this._coreService.decPrivateModes.cursorBlink??this._terminal.options.cursorBlink?this._cursorBlinkStateManager.value=new q0(()=>{this._requestRedrawCursor()},this._coreBrowserService):this._cursorBlinkStateManager.clear(),this._requestRedrawCursor()}_updateModel(t,r){let s=this._core,a=this._workCell,o,n,L,T,h,d,_,p,c,u,C,Q,m,R,F,E,y;t=pt(t,s.rows-1,0),r=pt(r,s.rows-1,0);let Y=this._coreService.decPrivateModes.cursorStyle??s.options.cursorStyle??"block",X=this._terminal.buffer.active.baseY+this._terminal.buffer.active.cursorY,A0=X-s.buffer.ydisp,t0=Math.min(this._terminal.buffer.active.cursorX,s.cols-1),L0=-1,A=this._coreService.isCursorInitialized&&!this._coreService.isCursorHidden&&(!this._cursorBlinkStateManager.value||this._cursorBlinkStateManager.value.isCursorVisible);this._model.cursor=void 0;let n0=false;for(n=t;n<=r;n++){L=n+s.buffer.ydisp;let a0=s.buffer.lines.get(L);if(!a0){for(this._model.lineLengths[n]=0,E=0;E=_,c=E,h.length>0&&E===h[0][0]&&p){u=h.shift();let q=this._model.selection.isCellSelected(this._terminal,u[0],L);for(F=u[0]+1;F=u[1],p?(d=true,a=new ge(a,T.translateToString(true,u[0],u[1]),u[1]-u[0]),c=u[1]-1):_=u[1]}if(Q=a.getChars(),m=a.getCode(),F=(n*s.cols+E)*4,!$&&a.isBlink()&&($=true),this._cellColorResolver.resolve(a,E,L,this.dimensions.device.cell.width,this.dimensions.device.cell.height),A&&L===X&&(E===t0&&(this._model.cursor={x:t0,y:A0,width:a.getWidth(),style:this._coreBrowserService.isFocused?Y:s.options.cursorInactiveStyle,cursorWidth:s.options.cursorWidth,dpr:this._devicePixelRatio},L0=t0+a.getWidth()-1),E>=t0&&E<=L0&&(this._coreBrowserService.isFocused&&Y==="block"||this._coreBrowserService.isFocused===false&&s.options.cursorInactiveStyle==="block")&&(this._cellColorResolver.result.fg=50331648|this._themeService.colors.cursorAccent.rgba>>8&16777215,this._cellColorResolver.result.bg=50331648|this._themeService.colors.cursor.rgba>>8&16777215)),this._textBlinkStateManager.isEnabled&&!this._textBlinkStateManager.isBlinkOn&&a.isBlink()&&(this._cellColorResolver.result.fg|=1073741824),m!==0&&(this._model.lineLengths[n]=E+1),!(this._model.cells[F]===m&&this._model.cells[F+1]===this._cellColorResolver.result.bg&&this._model.cells[F+2]===this._cellColorResolver.result.fg&&this._model.cells[F+3]===this._cellColorResolver.result.ext)&&(n0=true,Q.length>1&&(m|=lt),this._model.cells[F]=m,this._model.cells[F+1]=this._cellColorResolver.result.bg,this._model.cells[F+2]=this._cellColorResolver.result.fg,this._model.cells[F+3]=this._cellColorResolver.result.ext,R=a.getWidth(),this._glyphRenderer.value.updateCell(E,n,m,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext,Q,R,o),d)){for(a=this._workCell,E++;E<=c;E++)y=(n*s.cols+E)*4,this._nullModelCell(E,n,y,this._cellColorResolver.result.bg,this._cellColorResolver.result.fg,this._cellColorResolver.result.ext);E--}}this._setRowBlinkState(n,$)};n0&&this._rectangleRenderer.value.updateBackgrounds(this._model),this._rectangleRenderer.value.updateCursor(this._model),this._updateTextBlinkState()}_nullModelCell(t,r,s,a,o,n){;this._glyphRenderer.value.updateCell(t,r,0,a,o,n,"",0,0),this._model.cells[s]=0,this._model.cells[s+1]=a,this._model.cells[s+2]=o,this._model.cells[s+3]=n}_resetBlinkingRowState(){;this._rowHasBlinkingCells=new Array(this._terminal.rows).fill(false),this._rowHasBlinkingCellsCount=0}_setRowBlinkState(t,r){this._rowHasBlinkingCells[t]!==r&&(this._rowHasBlinkingCells[t]=r,this._rowHasBlinkingCellsCount+=r?1:-1)}_updateTextBlinkState(){this._textBlinkStateManager.setNeedsBlinkInViewport(this._rowHasBlinkingCellsCount>0)}_updateDimensions(){!this._charSizeService.width||!this._charSizeService.height||(this.dimensions.device.char.width=Math.floor(this._charSizeService.width*this._devicePixelRatio),this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*this._devicePixelRatio),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.top=this._optionsService.rawOptions.lineHeight===1?0:Math.round((this.dimensions.device.cell.height-this.dimensions.device.char.height)/2),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.char.left=Math.floor(this._optionsService.rawOptions.letterSpacing/2),this.dimensions.device.canvas.height=this._terminal.rows*this.dimensions.device.cell.height,this.dimensions.device.canvas.width=this._terminal.cols*this.dimensions.device.cell.width,this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/this._devicePixelRatio),this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/this._devicePixelRatio),this.dimensions.css.cell.height=this.dimensions.device.cell.height/this._devicePixelRatio,this.dimensions.css.cell.width=this.dimensions.device.cell.width/this._devicePixelRatio)}_setCanvasDevicePixelDimensions(t,r){;this._canvas.width===t&&this._canvas.height===r||(this._canvas.width=t,this._canvas.height=r,this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1,sync:true}))}_requestRedrawViewport(){this._onRequestRedraw.fire({start:0,end:this._terminal.rows-1})}_requestRedrawCursor(){let t=this._terminal.buffer.active.cursorY;this._onRequestRedraw.fire({start:t,end:t})}},ge=class extends s0{constructor(t,r,s){super();this.content=0;this.combinedData="";this.fg=t.fg,this.bg=t.bg,this.combinedData=r,this._width=s}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(t){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}};function pt(i5,e,t=0){return Math.max(Math.min(i5,e),t)}var Ct=class extends W{constructor(t){if(ue&&He()<16){let r={antialias:false,depth:false,preserveDrawingBuffer:true};if(!document.createElement("canvas").getContext("webgl2",r))throw new Error("WebGL2 is only supported on Safari 16 and above")}super();this._onChangeTextureAtlas=this._register(new U);this.onChangeTextureAtlas=this._onChangeTextureAtlas.event;this._onAddTextureAtlasCanvas=this._register(new U);this.onAddTextureAtlasCanvas=this._onAddTextureAtlasCanvas.event;this._onRemoveTextureAtlasCanvas=this._register(new U);this.onRemoveTextureAtlasCanvas=this._onRemoveTextureAtlasCanvas.event;this._onContextLoss=this._register(new U);this.onContextLoss=this._onContextLoss.event;this._customGlyphs=t?.customGlyphs??true,this._preserveDrawingBuffer=t?.preserveDrawingBuffer}activate(t){let r=t._core;if(!t.element){this._register(r.onWillOpen(()=>this.activate(t)));return}this._terminal=t;let s=r.coreService,a=r.optionsService,o=r,n=o._renderService,L=o._characterJoinerService,T=o._charSizeService,h=o._coreBrowserService,d=o._decorationService,_=o._logService,p=o._themeService;this._renderer=this._register(new Le(t,L,T,h,s,d,_,a,p,this._customGlyphs,this._preserveDrawingBuffer)),this._register(c0.forward(this._renderer.onContextLoss,this._onContextLoss)),this._register(c0.forward(this._renderer.onChangeTextureAtlas,this._onChangeTextureAtlas)),this._register(c0.forward(this._renderer.onAddTextureAtlasCanvas,this._onAddTextureAtlasCanvas)),this._register(c0.forward(this._renderer.onRemoveTextureAtlasCanvas,this._onRemoveTextureAtlasCanvas)),n.setRenderer(this._renderer),this._register(M(()=>{if(this._terminal._core._store._isDisposed)return;let c=this._terminal._core._renderService;c.setRenderer(this._terminal._core._createRenderer()),c.handleResize(t.cols,t.rows)}))}get textureAtlas(){return this._renderer?.textureAtlas}clearTextureAtlas(){this._renderer?.clearTextureAtlas()}};export{Ct as WebglAddon}; -diff -ruN a/src/GlyphRenderer.ts b/src/GlyphRenderer.ts +diff --git a/src/GlyphRenderer.ts b/src/GlyphRenderer.ts --- a/src/GlyphRenderer.ts +++ b/src/GlyphRenderer.ts @@ -74,7 +74,11 @@ @@ -142,7 +142,7 @@ diff -ruN a/src/GlyphRenderer.ts b/src/GlyphRenderer.ts this.invalidateAtlasTextures(); } -diff -ruN a/src/TextureAtlas.ts b/src/TextureAtlas.ts +diff --git a/src/TextureAtlas.ts b/src/TextureAtlas.ts --- a/src/TextureAtlas.ts +++ b/src/TextureAtlas.ts @@ -133,6 +133,7 @@ @@ -299,7 +299,7 @@ diff -ruN a/src/TextureAtlas.ts b/src/TextureAtlas.ts this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas); } activePage = this._overflowSizePage; -diff -ruN a/src/Types.ts b/src/Types.ts +diff --git a/src/Types.ts b/src/Types.ts --- a/src/Types.ts +++ b/src/Types.ts @@ -59,6 +59,9 @@ @@ -312,7 +312,7 @@ diff -ruN a/src/Types.ts b/src/Types.ts onAddTextureAtlasCanvas: IEvent; onRemoveTextureAtlasCanvas: IEvent; -diff -ruN a/src/WebglRenderer.ts b/src/WebglRenderer.ts +diff --git a/src/WebglRenderer.ts b/src/WebglRenderer.ts --- a/src/WebglRenderer.ts +++ b/src/WebglRenderer.ts @@ -386,7 +386,10 @@ diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index 10143d9019c..4dea7b1e3e2 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -6345,8 +6345,8 @@ "https://github.com/stablyai/orca/issues/16457", "https://github.com/stablyai/orca/pull/17128" ], - "invariant": "A fresh local renderer terminal spawn may recover from a saved startup cwd whose directory no longer exists only by spawning at the selected workspace root and printing a generic in-terminal notice; existing directories — including ones outside the worktree (#7685) — spawn as requested, and reattach, SSH, remote-runtime, runtime/API, and mobile callers keep exact cwd semantics. A long-lived POSIX shell whose cwd inode was deleted and replaced may run an extension-enabled OMP launch from the live path named by its logical PWD only in a subshell; the parent shell cwd, OMP argv, status extension, and exit status remain unchanged, while a genuinely unavailable path fails visibly without invoking OMP. A usable current directory remains authoritative when PWD is unset instead of being remapped to a workspace fallback.", - "oracle": "The shared resolver falls back to the workspace root only when the injected existence probe reports the resolved cwd missing and the workspace root present, and never probes floating terminals or a cwd equal to the root. The renderer sends cwdFallback only for fresh local IPC spawns, main honors it only when connectionId and sessionId are absent, WSL UNC paths never engage the probe-based fallback, main returns fallback metadata only after an actual fallback, the IPC transport preserves that metadata, and the connection layer writes a generic notice that omits the missing path. In real interactive Bash and Zsh PTYs, unset PWD in a usable nested directory and require OMP to stay there rather than remap to ORCA_WORKTREE_PATH; then delete and recreate the active project path, require OMP to observe the replacement inode with byte-exact extension argv and its nonzero status preserved, require the parent shell to remain on the stale inode, and finally delete the replacement and require an actionable failure before the fake OMP binary runs again.", + "invariant": "A fresh local renderer terminal spawn may recover from a saved startup cwd whose directory no longer exists only by spawning at the selected workspace root and printing a generic in-terminal notice; existing directories — including ones outside the worktree (#7685) — spawn as requested, and reattach, SSH, remote-runtime, runtime/API, and mobile callers keep exact cwd semantics. A long-lived POSIX shell whose cwd inode was deleted and replaced may run a wrapped OMP command from the live path named by its logical PWD only in a subshell; the parent shell cwd, OMP argv, status extension, and exit status remain unchanged, while a genuinely unavailable path fails visibly without invoking OMP. A usable physical cwd remains authoritative when PWD is unset or names a removed logical symlink instead of being remapped to a workspace fallback.", + "oracle": "The shared resolver falls back to the workspace root only when the injected existence probe reports the resolved cwd missing and the workspace root present, and never probes floating terminals or a cwd equal to the root. The renderer sends cwdFallback only for fresh local IPC spawns, main honors it only when connectionId and sessionId are absent, WSL UNC paths never engage the probe-based fallback, main returns fallback metadata only after an actual fallback, the IPC transport preserves that metadata, and the connection layer writes a generic notice that omits the missing path. In real interactive Bash and Zsh PTYs, unset PWD and remove a logical symlink while the physical cwd stays usable, requiring OMP to remain there; then delete and recreate the active project path, require extension-enabled and extension-skipping invocations to observe the replacement inode with byte-exact argv and nonzero status preserved, require the parent shell to remain on the stale inode, unset PWD and require recovery through ORCA_WORKTREE_PATH, clear every logical fallback and require an actionable failure without invoking OMP, and finally delete the replacement and require the same for the missing PWD path.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/shared/terminal-startup-cwd.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/pty-spawn-cwd-fallback.test.ts src/main/ipc/pty-wsl-cwd-validation.test.ts", @@ -6410,6 +6410,10 @@ "assertions": [ "real Bash and Zsh PTYs rebind OMP to a recreated cwd inode without changing the parent shell", "an unset PWD with a usable cwd stays unset and does not remap OMP to ORCA_WORKTREE_PATH", + "a removed logical symlink does not invalidate its still-usable physical cwd", + "extension-skipping commands such as omp --version still recover the cwd without gaining extension argv", + "an unset PWD on a stale inode recovers through ORCA_WORKTREE_PATH", + "an unset PWD on a stale inode without a logical fallback fails visibly before invoking OMP", "extension argv and a nonzero OMP exit status survive the recovery subshell", "a subsequently missing logical cwd prints an actionable error and does not invoke OMP again" ] @@ -6465,7 +6469,7 @@ "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/pty/omp-shell-wrapper.node-pty.test.ts src/main/pty/omp-shell-wrapper-alias-safety.test.ts src/main/shell-wrapper-generated-file-snapshot.test.ts", "result": "passed", "durationSeconds": 3, - "summary": "3 test files passed; real Bash and Zsh PTYs covered unset-PWD authority, stale-inode recovery, parent-shell isolation, extension argv, exit status, missing-path visibility, alias safety, and generated local/daemon/relay parity." + "summary": "3 test files passed; real Bash and Zsh PTYs covered usable physical cwd authority, stale-inode recovery with set and unset PWD, extension-enabled and extension-skipping argv, parent-shell isolation, exit status, missing-path visibility, alias safety, and generated local/daemon/relay parity." } ], "runtimeBudget": { @@ -6482,7 +6486,7 @@ }, "performanceBudget": { "required": true, - "evidence": "The spawn recovery adds at most two statSync probes on the fresh-local spawn path (the provider already stats the same paths during validation) and one bounded terminal write only when fallback actually occurs. Each extension-enabled OMP launch adds a constant number of shell filesystem predicates; only a detected stale/unusable cwd creates one short recovery subshell. No polling, retry, provider listing, hidden-pane work, startup awaits, extra OMP subprocesses, or render-loop work was added." + "evidence": "The spawn recovery adds at most two statSync probes on the fresh-local spawn path (the provider already stats the same paths during validation) and one bounded terminal write only when fallback actually occurs. Each wrapped OMP launch adds a constant number of shell filesystem predicates; only a detected stale/unusable cwd creates one short recovery subshell. No polling, retry, provider listing, hidden-pane work, startup awaits, extra OMP subprocesses, or render-loop work was added." }, "promotionCriteria": [ "Attach CI evidence for all declared test files.", diff --git a/config/scripts/build-native-for-platform.mjs b/config/scripts/build-native-for-platform.mjs index c90ecfd4146..d6294f4b5c7 100755 --- a/config/scripts/build-native-for-platform.mjs +++ b/config/scripts/build-native-for-platform.mjs @@ -1,6 +1,7 @@ #!/usr/bin/env node import { spawnSync } from 'node:child_process' +import { resolvePnpmCliInvocation } from './pnpm-cli-invocation.mjs' if (process.platform === 'win32') { runNodeScript('config/scripts/build-windows-cli-launcher.mjs') @@ -18,14 +19,8 @@ runPnpmScript('build:notification-status-macos') process.exit(0) function runPnpmScript(scriptName) { - const npmExecPath = process.env.npm_execpath - const command = npmExecPath - ? process.execPath - : process.platform === 'win32' - ? 'pnpm.cmd' - : 'pnpm' - const args = npmExecPath ? [npmExecPath, 'run', scriptName] : ['run', scriptName] - const result = spawnSync(command, args, { stdio: 'inherit' }) + const { command, prefixArgs, shell } = resolvePnpmCliInvocation() + const result = spawnSync(command, [...prefixArgs, 'run', scriptName], { stdio: 'inherit', shell }) if (result.signal) { process.kill(process.pid, result.signal) diff --git a/config/scripts/build-windows-process-tree-relay-addon.mjs b/config/scripts/build-windows-process-tree-relay-addon.mjs index 364335e537c..d3b9db939cd 100644 --- a/config/scripts/build-windows-process-tree-relay-addon.mjs +++ b/config/scripts/build-windows-process-tree-relay-addon.mjs @@ -29,11 +29,11 @@ import { readSync, writeFileSync } from 'node:fs' -import { createRequire } from 'node:module' -import { dirname, join, resolve } from 'node:path' +import { join, resolve } from 'node:path' import { RELAY_WINDOWS_PROCESS_TREE_FILENAME } from '../../src/shared/relay-artifacts.ts' import { nodeGypRebuildInvocation, + stageWindowsProcessTreeNodeAddonApiHeaders, WINDOWS_PROCESS_TREE_PACKAGE_DIR as PACKAGE_DIR } from './windows-process-tree-gyp-rebuild.mjs' @@ -96,10 +96,6 @@ function assertPatchApplied() { function applyWindowsProcessTreeBuildFixes() { const bindingPath = join(PACKAGE_DIR, 'binding.gyp') const processPath = join(PACKAGE_DIR, 'src', 'process.cc') - const nodeAddonApiDir = dirname( - createRequire(join(PACKAGE_DIR, 'package.json')).resolve('node-addon-api/package.json') - ) - const stagedHeaderDir = join(PACKAGE_DIR, 'deps', 'node-addon-api') let bindingGyp = readFileSync(bindingPath, 'utf8') let processCc = readFileSync(processPath, 'utf8') const originalBinding = bindingGyp @@ -134,10 +130,7 @@ function applyWindowsProcessTreeBuildFixes() { if (processCc !== originalProcess) { writeFileSync(processPath, processCc) } - mkdirSync(stagedHeaderDir, { recursive: true }) - for (const header of ['napi.h', 'napi-inl.h', 'napi-inl.deprecated.h']) { - copyFileSync(join(nodeAddonApiDir, header), join(stagedHeaderDir, header)) - } + stageWindowsProcessTreeNodeAddonApiHeaders(PACKAGE_DIR) if (bindingGyp !== originalBinding || processCc !== originalProcess) { console.warn('[windows-process-tree] Repaired un-applied pnpm patch hunks before build.') } diff --git a/config/scripts/computer-e2e-workflow.test.mjs b/config/scripts/computer-e2e-workflow.test.mjs index 36a5d701f5e..8e7d9a70197 100644 --- a/config/scripts/computer-e2e-workflow.test.mjs +++ b/config/scripts/computer-e2e-workflow.test.mjs @@ -171,7 +171,7 @@ describe('computer-use e2e workflow', () => { expect(checkout.with['persist-credentials'], jobName).toBe(false) expect(install.with['native-runtime'], jobName).toBe('electron') expect( - job.steps.some((step) => step.uses === 'pnpm/action-setup@v6'), + job.steps.some((step) => step.uses === 'pnpm/setup@v2'), jobName ).toBe(false) expect( diff --git a/config/scripts/ensure-native-runtime.mjs b/config/scripts/ensure-native-runtime.mjs index 424b671b11e..a4cc6db8843 100644 --- a/config/scripts/ensure-native-runtime.mjs +++ b/config/scripts/ensure-native-runtime.mjs @@ -377,7 +377,8 @@ function rebuildNodeRuntimeModules(moduleNames) { } function runPnpm(args, { cwd = projectDir } = {}) { - const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm' + // cmd.exe resolves both Corepack's pnpm.cmd and pnpm 12's native pnpm.exe. + const command = 'pnpm' const env = process.platform === 'linux' && args.includes('node-gyp') ? { ...process.env, CXXFLAGS: `${process.env.CXXFLAGS ?? ''} -std=gnu++2a`.trim() } diff --git a/config/scripts/install-node-dependencies-action.test.mjs b/config/scripts/install-node-dependencies-action.test.mjs index a90747513a1..3b20a0eb07e 100644 --- a/config/scripts/install-node-dependencies-action.test.mjs +++ b/config/scripts/install-node-dependencies-action.test.mjs @@ -24,10 +24,15 @@ function createFixture() { for (const directory of [workspace, detachedCwd]) { writeFileSync(join(directory, 'package.json'), '{"name":"fixture"}\n') writeFileSync(join(directory, 'pnpm-lock.yaml'), 'lockfileVersion: 9\n') + writeFileSync(join(directory, 'pnpm-workspace.yaml'), 'packages: []\n') } expect(run('git', ['init', '-q'], { cwd: workspace }).status).toBe(0) - expect(run('git', ['add', 'package.json', 'pnpm-lock.yaml'], { cwd: workspace }).status).toBe(0) + expect( + run('git', ['add', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'], { + cwd: workspace + }).status + ).toBe(0) const pnpm = join(bin, 'pnpm') writeFileSync(pnpm, '#!/bin/sh\nexit 0\n') @@ -76,7 +81,8 @@ describe('install-node-dependencies action', () => { it.each([ ['package.json', '{"name":"changed"}\n'], - ['pnpm-lock.yaml', 'lockfileVersion: 9\nchanged: true\n'] + ['pnpm-lock.yaml', 'lockfileVersion: 9\nchanged: true\n'], + ['pnpm-workspace.yaml', 'packages: []\nchanged: true\n'] ])('rejects a changed %s when the composite step cwd is detached', (file, contents) => { const fixture = createFixture() try { diff --git a/config/scripts/package-electron-runtime-contract.test.mjs b/config/scripts/package-electron-runtime-contract.test.mjs index 64b2f96505a..05ad5bd47d7 100644 --- a/config/scripts/package-electron-runtime-contract.test.mjs +++ b/config/scripts/package-electron-runtime-contract.test.mjs @@ -8,14 +8,13 @@ import { relayArtifactFilenames } from '../../src/shared/relay-artifacts.ts' const projectDir = resolve(import.meta.dirname, '../..') const require = createRequire(import.meta.url) const { createPackagedRuntimeNodeModuleResources } = require('../packaged-runtime-node-modules.cjs') -const packageJson = JSON.parse(readFileSync(join(projectDir, 'package.json'), 'utf8')) +const readProject = (file) => readFileSync(join(projectDir, file), 'utf8') +const packageJson = JSON.parse(readProject('package.json')) +const pnpmWorkspace = parse(readProject('pnpm-workspace.yaml')) describe('Electron runtime package contract', () => { it('keeps shared WebGL atlas invalidation reproducible from vendored source', () => { - const patch = readFileSync( - join(projectDir, 'config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch'), - 'utf8' - ) + const patch = readProject('config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch') expect(patch).toContain('readonly clearModelGeneration: number') expect(patch).toContain('const generation = this._atlas.clearModelGeneration') @@ -26,7 +25,7 @@ describe('Electron runtime package contract', () => { it('keeps root postinstall as the single Electron binary install owner', () => { expect(packageJson.scripts.postinstall).toBe('node config/scripts/rebuild-native-deps.mjs') - expect(packageJson.pnpm.onlyBuiltDependencies).not.toContain('electron') + expect(pnpmWorkspace.allowBuilds).not.toHaveProperty('electron') }) it('keeps the native Windows registry addon optional and platform-gated', () => { @@ -41,7 +40,7 @@ describe('Electron runtime package contract', () => { expect(packageJson.optionalDependencies['windows-native-registry']).toBe('3.2.2') // Why: pnpm installs optional target architectures on every host; the root // Windows-only rebuild owns this addon so macOS/Linux never run node-gyp for it. - expect(packageJson.pnpm.onlyBuiltDependencies).not.toContain('windows-native-registry') + expect(pnpmWorkspace.allowBuilds['windows-native-registry']).toBe(false) // Why assert the guard and the member separately: the list now carries more // than one addon, so pinning the whole literal only tested its formatting. expect(rebuildScript).toContain("rebuildPlatform === 'win32'") @@ -80,14 +79,14 @@ describe('Electron runtime package contract', () => { expect(packageJson.optionalDependencies['@vscode/windows-process-tree']).toBe('0.8.0') // Why: same rule as the registry addon -- pnpm installs optional deps on // every host, so macOS/Linux must never run node-gyp for a Windows addon. - expect(packageJson.pnpm.onlyBuiltDependencies).not.toContain('@vscode/windows-process-tree') + expect(pnpmWorkspace.allowBuilds['@vscode/windows-process-tree']).toBe(false) expect(rebuildScript).toContain("'@vscode/windows-process-tree'") expect(ensureScript).toContain("'@vscode/windows-process-tree'") // Why pin the patch: the upstream binding.gyp requires Spectre-mitigated // libraries our build agents do not carry, and the enumeration stops after // 1024 processes -- on a busy host that silently hides the very descendants // teardown is looking for. - expect(packageJson.pnpm.patchedDependencies['@vscode/windows-process-tree@0.8.0']).toBe( + expect(pnpmWorkspace.patchedDependencies['@vscode/windows-process-tree@0.8.0']).toBe( 'config/patches/@vscode__windows-process-tree@0.8.0.patch' ) const packageTargets = { diff --git a/config/scripts/pnpm-cli-invocation.mjs b/config/scripts/pnpm-cli-invocation.mjs new file mode 100644 index 00000000000..8378efd7f37 --- /dev/null +++ b/config/scripts/pnpm-cli-invocation.mjs @@ -0,0 +1,26 @@ +// pnpm 12's npm_execpath is a native binary; feeding it to node broke hourly/adhoc macOS builds. + +const JS_CLI_EXTENSION = /\.[cm]?js$/i + +export function resolvePnpmCliInvocation({ + npmExecPath = process.env.npm_execpath, + nodeExecPath = process.execPath, + platform = process.platform +} = {}) { + if (typeof npmExecPath === 'string' && npmExecPath.length > 0) { + if (JS_CLI_EXTENSION.test(npmExecPath)) { + return { command: nodeExecPath, prefixArgs: [npmExecPath], shell: false } + } + return { + command: npmExecPath, + prefixArgs: [], + shell: platform === 'win32' && /\.(cmd|bat)$/i.test(npmExecPath) + } + } + + return { + command: platform === 'win32' ? 'pnpm.cmd' : 'pnpm', + prefixArgs: [], + shell: platform === 'win32' + } +} diff --git a/config/scripts/pnpm-cli-invocation.test.mjs b/config/scripts/pnpm-cli-invocation.test.mjs new file mode 100644 index 00000000000..191599e166d --- /dev/null +++ b/config/scripts/pnpm-cli-invocation.test.mjs @@ -0,0 +1,100 @@ +import { readFileSync } from 'node:fs' +import { describe, expect, it } from 'vitest' +import { resolvePnpmCliInvocation } from './pnpm-cli-invocation.mjs' + +const nodeExecPath = '/usr/local/bin/node' + +describe('resolvePnpmCliInvocation', () => { + it('runs a JS CLI through node so older pnpm.cjs still works', () => { + expect( + resolvePnpmCliInvocation({ + npmExecPath: '/Users/runner/setup-pnpm/node_modules/pnpm/bin/pnpm.cjs', + nodeExecPath, + platform: 'darwin' + }) + ).toEqual({ + command: nodeExecPath, + prefixArgs: ['/Users/runner/setup-pnpm/node_modules/pnpm/bin/pnpm.cjs'], + shell: false + }) + }) + + it('executes pnpm 12 native binaries directly instead of through node', () => { + expect( + resolvePnpmCliInvocation({ + npmExecPath: '/Users/runner/setup-pnpm/pnpm', + nodeExecPath, + platform: 'darwin' + }) + ).toEqual({ + command: '/Users/runner/setup-pnpm/pnpm', + prefixArgs: [], + shell: false + }) + }) + + it('does not wrap a Windows native pnpm.exe in node', () => { + expect( + resolvePnpmCliInvocation({ + npmExecPath: 'C:\\hostedtoolcache\\pnpm.exe', + nodeExecPath: 'C:\\Program Files\\nodejs\\node.exe', + platform: 'win32' + }) + ).toEqual({ + command: 'C:\\hostedtoolcache\\pnpm.exe', + prefixArgs: [], + shell: false + }) + }) + + it('shells out for a Windows .cmd wrapper', () => { + expect( + resolvePnpmCliInvocation({ + npmExecPath: 'C:\\Users\\runner\\pnpm.cmd', + nodeExecPath: 'C:\\Program Files\\nodejs\\node.exe', + platform: 'win32' + }) + ).toEqual({ + command: 'C:\\Users\\runner\\pnpm.cmd', + prefixArgs: [], + shell: true + }) + }) + + it('treats .js and .mjs CLIs the same as .cjs', () => { + for (const npmExecPath of ['/opt/pnpm.js', '/opt/pnpm.mjs']) { + expect(resolvePnpmCliInvocation({ npmExecPath, nodeExecPath, platform: 'linux' })).toEqual({ + command: nodeExecPath, + prefixArgs: [npmExecPath], + shell: false + }) + } + }) + + it('falls back to PATH pnpm when npm_execpath is unset', () => { + expect( + resolvePnpmCliInvocation({ npmExecPath: undefined, nodeExecPath, platform: 'darwin' }) + ).toEqual({ command: 'pnpm', prefixArgs: [], shell: false }) + expect(resolvePnpmCliInvocation({ npmExecPath: '', nodeExecPath, platform: 'linux' })).toEqual({ + command: 'pnpm', + prefixArgs: [], + shell: false + }) + expect( + resolvePnpmCliInvocation({ npmExecPath: undefined, nodeExecPath, platform: 'win32' }) + ).toEqual({ command: 'pnpm.cmd', prefixArgs: [], shell: true }) + }) +}) + +describe('pnpm 12 native-cli callers', () => { + it('reinvokes pnpm through the helper rather than `node $npm_execpath`', () => { + for (const file of [ + './build-native-for-platform.mjs', + './run-ssh-docker-bulk-open-freeze-e2e.mjs' + ]) { + const source = readFileSync(new URL(file, import.meta.url), 'utf8') + expect(source).toContain("from './pnpm-cli-invocation.mjs'") + expect(source).not.toMatch(/process\.execPath,\s*\[\s*(?:pnpmEntry|npmExecPath)/) + } + }) +}) diff --git a/config/scripts/pr-workflow-parallelism.test.mjs b/config/scripts/pr-workflow-parallelism.test.mjs index f67abe5ee6d..40c110fc8d9 100644 --- a/config/scripts/pr-workflow-parallelism.test.mjs +++ b/config/scripts/pr-workflow-parallelism.test.mjs @@ -9,6 +9,7 @@ const dependencyAction = parse( readFileSync('.github/actions/install-node-dependencies/action.yml', 'utf8') ) const packageJson = JSON.parse(readFileSync('package.json', 'utf8')) +const pnpmWorkspace = parse(readFileSync('pnpm-workspace.yaml', 'utf8')) const shellContractFiles = [ 'src/main/daemon/repro-13767-shell-ready-marker-lost-to-exec.test.ts', 'src/main/daemon/shell-ready.test.ts', @@ -224,7 +225,10 @@ describe('PR workflow parallelism', () => { expect(pnpmIndex).toBeLessThan(nodeIndex) expect(pnpmIndex).toBeLessThan(requestedNodeIndex) const packageManagerVersion = /^pnpm@([^+]+)/.exec(packageJson.packageManager)?.[1] - expect(steps[pnpmIndex].with.version).toBe(packageManagerVersion) + expect(packageManagerVersion).toBe('12.0.0') + expect(steps[pnpmIndex].uses).toBe('pnpm/setup@v2') + expect(steps[pnpmIndex].with.version).toBeUndefined() + expect(steps[pnpmIndex].with.install).toBe(false) expect(steps[nodeIndex].with.cache).toBe('pnpm') expect(steps[nodeIndex].if).toBe("inputs.node-version == ''") expect(steps[requestedNodeIndex].if).toBe("inputs.node-version != ''") @@ -232,20 +236,20 @@ describe('PR workflow parallelism', () => { expect(steps[requestedNodeIndex].with.cache).toBe('pnpm') }) - it('pins every direct pnpm setup to the repository package-manager version', () => { - const packageManagerVersion = /^pnpm@([^+]+)/.exec(packageJson.packageManager)?.[1] + it('uses the repository package-manager version for every direct pnpm setup', () => { const directSetups = globSync('.github/workflows/*.yml').flatMap((workflowPath) => { const parsed = parse(readFileSync(workflowPath, 'utf8')) return Object.values(parsed.jobs ?? {}).flatMap((job) => (job.steps ?? []) - .filter((step) => step.uses === 'pnpm/action-setup@v6') + .filter((step) => step.uses === 'pnpm/setup@v2') .map((step) => ({ workflowPath, step })) ) }) expect(directSetups.length).toBeGreaterThan(0) for (const { workflowPath, step } of directSetups) { - expect(step.with?.version, workflowPath).toBe(packageManagerVersion) + expect(step.with?.version, workflowPath).toBeUndefined() + expect(step.with?.install, workflowPath).toBe(false) } }) @@ -293,15 +297,15 @@ describe('PR workflow parallelism', () => { expect(dependencyInstall.run).toContain('--frozen-lockfile') expect(dependencyInstall.run).not.toContain('--no-frozen-lockfile') expect(dependencyInstall.run).toContain( - 'git -C "$GITHUB_WORKSPACE" diff --exit-code -- package.json pnpm-lock.yaml' + 'git -C "$GITHUB_WORKSPACE" diff --exit-code -- package.json pnpm-lock.yaml pnpm-workspace.yaml' ) expect(dependencyInstall.run).toContain('--ignore-scripts') expect(dependencyInstall.run).not.toContain('--os=') expect(dependencyInstall.run).not.toContain('--cpu=') - expect(packageJson.pnpm.supportedArchitectures.os).toEqual( + expect(pnpmWorkspace.supportedArchitectures.os).toEqual( expect.arrayContaining(['current', 'win32']) ) - expect(packageJson.pnpm.supportedArchitectures.cpu).toContain('current') + expect(pnpmWorkspace.supportedArchitectures.cpu).toContain('current') const prepareRuntime = dependencyAction.runs.steps.find( (step) => step.name === 'Prepare native runtime' ) diff --git a/config/scripts/rebuild-native-deps.mjs b/config/scripts/rebuild-native-deps.mjs index 4eca4bac33a..9bf61b679ed 100644 --- a/config/scripts/rebuild-native-deps.mjs +++ b/config/scripts/rebuild-native-deps.mjs @@ -20,6 +20,7 @@ import { rebuild } from '@electron/rebuild' import { execFileSync, spawnSync } from 'node:child_process' +import { stageWindowsProcessTreeNodeAddonApiHeaders } from './windows-process-tree-gyp-rebuild.mjs' import { copyFileSync, existsSync, @@ -132,6 +133,14 @@ if (!ignoreModules.includes('cpu-features')) { } } +if ( + rebuildPlatform === 'win32' && + modulesToRebuild.includes('@vscode/windows-process-tree') && + existsSync(join(projectDir, 'node_modules', '@vscode', 'windows-process-tree', 'package.json')) +) { + stageWindowsProcessTreeNodeAddonApiHeaders() +} + try { await rebuild({ buildPath: projectDir, diff --git a/config/scripts/rebuild-native-deps.test.mjs b/config/scripts/rebuild-native-deps.test.mjs index 5ebc39dfcaa..31676b92e55 100644 --- a/config/scripts/rebuild-native-deps.test.mjs +++ b/config/scripts/rebuild-native-deps.test.mjs @@ -21,6 +21,9 @@ const sourceInstallScriptPath = fileURLToPath( const sourceNodePtyJobOwnershipPath = fileURLToPath( new URL('./node-pty-job-ownership.cjs', import.meta.url) ) +const sourceWindowsProcessTreeGypRebuildPath = fileURLToPath( + new URL('./windows-process-tree-gyp-rebuild.mjs', import.meta.url) +) describe('rebuild-native-deps Electron install fallback', () => { it('continues non-strict postinstall when Electron retry download fails', () => { @@ -159,6 +162,41 @@ describe('rebuild-native-deps patched node-pty rebuild', () => { } ) + it('stages windows-process-tree node-addon-api headers before a Windows rebuild', () => { + const projectDir = mkTempProject() + + try { + writeFakeUsableElectronPackage(projectDir, { platform: 'win32' }) + writeFakeElectronRebuild(projectDir) + writeFakeNodePtyConptyPayload(projectDir, 'x64') + writeFakeWindowsProcessTreeWithNodeAddonApi(projectDir) + + const result = runRebuildScript( + projectDir, + { npm_config_platform: 'win32', npm_config_arch: 'x64' }, + ['--platform=win32', '--arch=x64', '--force'] + ) + + expect(result.status, result.stderr).toBe(0) + expect( + readFileSync( + join( + projectDir, + 'node_modules', + '@vscode', + 'windows-process-tree', + 'deps', + 'node-addon-api', + 'napi.h' + ), + 'utf8' + ) + ).toBe('// napi.h\n') + } finally { + rmSync(projectDir, { recursive: true, force: true }) + } + }) + it('restores the ConPTY runtime payload after a Windows Electron rebuild', () => { const projectDir = mkTempProject() @@ -344,6 +382,10 @@ function mkTempProject() { sourceNodePtyJobOwnershipPath, join(projectDir, 'config', 'scripts', 'node-pty-job-ownership.cjs') ) + copyFileSync( + sourceWindowsProcessTreeGypRebuildPath, + join(projectDir, 'config', 'scripts', 'windows-process-tree-gyp-rebuild.mjs') + ) return projectDir } @@ -578,6 +620,18 @@ function writeFakeWindowsProcessTree(projectDir) { writeFileSync(join(processTreeDir, 'index.js'), 'module.exports = {}\n') } +function writeFakeWindowsProcessTreeWithNodeAddonApi(projectDir) { + const processTreeDir = join(projectDir, 'node_modules', '@vscode', 'windows-process-tree') + const nodeAddonApiDir = join(processTreeDir, 'node_modules', 'node-addon-api') + mkdirSync(nodeAddonApiDir, { recursive: true }) + writeFileSync(join(processTreeDir, 'package.json'), '{"dependencies":{"node-addon-api":"*"}}\n') + writeFileSync(join(processTreeDir, 'index.js'), 'module.exports = {}\n') + writeFileSync(join(nodeAddonApiDir, 'package.json'), '{"name":"node-addon-api"}\n') + writeFileSync(join(nodeAddonApiDir, 'napi.h'), '// napi.h\n') + writeFileSync(join(nodeAddonApiDir, 'napi-inl.h'), '// napi-inl.h\n') + writeFileSync(join(nodeAddonApiDir, 'napi-inl.deprecated.h'), '// napi-inl.deprecated.h\n') +} + function writeNodePtyPatchFile(projectDir) { mkdirSync(join(projectDir, 'config', 'patches'), { recursive: true }) writeFileSync(join(projectDir, 'config', 'patches', 'node-pty@1.1.0.patch'), 'patch marker\n') diff --git a/config/scripts/regenerate-xterm-patches.mjs b/config/scripts/regenerate-xterm-patches.mjs index 160d075aee2..a2da6d9da2d 100644 --- a/config/scripts/regenerate-xterm-patches.mjs +++ b/config/scripts/regenerate-xterm-patches.mjs @@ -22,13 +22,15 @@ const DEFAULT_REPO_ROOT = path.resolve(import.meta.dirname, '..', '..') const MANIFEST_RELATIVE_PATH = path.join('config', 'patches', 'xterm-upstream.json') /** - * Flags pnpm@10 passes to `git diff` in its own `diffFolders()`. A patch built + * Flags pnpm@12 passes to `git diff` in its own `diff_folders()`. A patch built * with anything else is a patch pnpm may re-diff differently on the next * `pnpm patch-commit`, so the byte-comparison gate would never settle. */ export const PNPM_DIFF_FLAGS = [ '-c', 'core.safecrlf=false', + '-c', + 'core.quotePath=false', 'diff', '--src-prefix=a/', '--dst-prefix=b/', @@ -38,7 +40,8 @@ export const PNPM_DIFF_FLAGS = [ '--no-index', '--text', '--no-ext-diff', - '--no-color' + '--no-color', + '--' ] /** @@ -47,14 +50,12 @@ export const PNPM_DIFF_FLAGS = [ */ export const CHECKOUT_DIFF_FLAGS = PNPM_DIFF_FLAGS.filter((flag) => flag !== '--no-index') -/** Blanks the vars pnpm blanks so user and system git config cannot reach the diff. */ +/** Applies pnpm's git config isolation so local machine settings cannot change the patch. */ export function pnpmDiffEnvironment(baseEnvironment = process.env) { return { ...baseEnvironment, GIT_CONFIG_NOSYSTEM: '1', - HOME: '', - XDG_CONFIG_HOME: '', - USERPROFILE: '' + GIT_CONFIG_GLOBAL: '/dev/null' } } @@ -216,7 +217,7 @@ export function patchHash(patchText) { function lockfilePatchHashPattern(packageKey) { // Unscoped keys such as `node-pty@1.1.0` are emitted unquoted. - return new RegExp(`(^ '?${escapeRegExp(packageKey)}'?:\\n hash: )([0-9a-f]{64})$`, 'm') + return new RegExp(`(^ '?${escapeRegExp(packageKey)}'?: )([0-9a-f]{64})$`, 'm') } export function readLockfilePatchHash(lockfileText, packageKey) { @@ -507,7 +508,7 @@ function diffFolders(folderA, folderB) { /** The source of truth for the hand-written half: what the checkout itself holds. */ function diffCheckoutSource(packageRoot) { - return run('git', [...CHECKOUT_DIFF_FLAGS, '--', 'src/'], { + return run('git', [...CHECKOUT_DIFF_FLAGS, 'src/'], { cwd: packageRoot, env: pnpmDiffEnvironment(), maxBuffer: 64 * 1024 * 1024 diff --git a/config/scripts/regenerate-xterm-patches.test.mjs b/config/scripts/regenerate-xterm-patches.test.mjs index ac9f9a7ca52..2c4a34dc501 100644 --- a/config/scripts/regenerate-xterm-patches.test.mjs +++ b/config/scripts/regenerate-xterm-patches.test.mjs @@ -98,6 +98,8 @@ describe('pnpm diff format', () => { expect(PNPM_DIFF_FLAGS).toEqual([ '-c', 'core.safecrlf=false', + '-c', + 'core.quotePath=false', 'diff', '--src-prefix=a/', '--dst-prefix=b/', @@ -107,18 +109,18 @@ describe('pnpm diff format', () => { '--no-index', '--text', '--no-ext-diff', - '--no-color' + '--no-color', + '--' ]) }) - it('blanks the config-bearing environment variables', () => { + it('matches pnpm git config isolation', () => { const environment = pnpmDiffEnvironment({ PATH: '/usr/bin', HOME: '/Users/someone' }) expect(environment).toMatchObject({ PATH: '/usr/bin', GIT_CONFIG_NOSYSTEM: '1', - HOME: '', - XDG_CONFIG_HOME: '', - USERPROFILE: '' + GIT_CONFIG_GLOBAL: '/dev/null', + HOME: '/Users/someone' }) }) @@ -350,12 +352,8 @@ describe('manifest guards', () => { describe('lockfile coupling', () => { const lockfile = [ 'patchedDependencies:', - " '@xterm/xterm@6.1.0-beta.287':", - ` hash: ${'0'.repeat(64)}`, - ' path: config/patches/@xterm__xterm@6.1.0-beta.287.patch', - ' node-pty@1.1.0:', - ` hash: ${'1'.repeat(64)}`, - ' path: config/patches/node-pty@1.1.0.patch', + ` '@xterm/xterm@6.1.0-beta.287': ${'0'.repeat(64)}`, + ` node-pty@1.1.0: ${'1'.repeat(64)}`, 'snapshots:', ` '@xterm/addon-fit@0.12.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=${'0'.repeat(64)}))':`, ` '@xterm/xterm': 6.1.0-beta.287(patch_hash=${'0'.repeat(64)})`, @@ -396,7 +394,10 @@ describe('lockfile coupling', () => { it('reports a lockfile stale in its resolution keys alone', () => { const key = '@xterm/xterm@6.1.0-beta.287' - const halfUpdated = lockfile.replace(`hash: ${'0'.repeat(64)}`, `hash: ${'a'.repeat(64)}`) + const halfUpdated = lockfile.replace( + `'@xterm/xterm@6.1.0-beta.287': ${'0'.repeat(64)}`, + `'@xterm/xterm@6.1.0-beta.287': ${'a'.repeat(64)}` + ) expect(readLockfilePatchHash(halfUpdated, key)).toBe('a'.repeat(64)) expect(lockfilePatchHashIsStale(halfUpdated, key, 'a'.repeat(64))).toBe(true) diff --git a/config/scripts/release-cut-token-permissions.test.mjs b/config/scripts/release-cut-token-permissions.test.mjs index 24f138723c9..2478087ba8a 100644 --- a/config/scripts/release-cut-token-permissions.test.mjs +++ b/config/scripts/release-cut-token-permissions.test.mjs @@ -8,6 +8,7 @@ const EXPECTED_MATRIX = { '.github/workflows/e2e.yml#build': { contents: 'read' }, '.github/workflows/e2e.yml#changed-e2e': { contents: 'read' }, '.github/workflows/e2e.yml#e2e': { contents: 'read' }, + '.github/workflows/e2e.yml#prepare-native-cache': { contents: 'read' }, '.github/workflows/e2e.yml#ssh-docker-watcher-isolation': { contents: 'read' }, '.github/workflows/homebrew-bump.yml#bump-cask': { contents: 'read' }, '.github/workflows/release-mac-build.yml#build-mac': { contents: 'write' }, diff --git a/config/scripts/release-e2e-dispatch-contract.test.mjs b/config/scripts/release-e2e-dispatch-contract.test.mjs index d48c7b3fa30..5fd4503d4e3 100644 --- a/config/scripts/release-e2e-dispatch-contract.test.mjs +++ b/config/scripts/release-e2e-dispatch-contract.test.mjs @@ -46,6 +46,28 @@ describe('release E2E dispatch contract', () => { expect(refInput.required).toBe(false) }) + it('overlaps the relay bundle with the Electron build', () => { + const buildStep = e2eWorkflow.jobs.build.steps.find((step) => step.name === 'Build E2E outputs') + + expect(buildStep.run).toContain('pnpm run build:relay &') + expect(buildStep.run).toContain('relay_pid=$!') + expect(buildStep.run).toContain('wait "$relay_pid"') + expect(buildStep.run).toContain('pnpm run build:web-from-renderer') + }) + + it('primes the Electron native cache before every E2E consumer', () => { + const primer = e2eWorkflow.jobs['prepare-native-cache'] + expect(primer.steps).toBeDefined() + expect( + primer.steps.find((step) => step.uses === './.github/actions/install-node-dependencies').with + ).toEqual({ + 'native-runtime': 'electron' + }) + for (const jobName of ['e2e', 'changed-e2e', 'ssh-docker-watcher-isolation']) { + expect(e2eWorkflow.jobs[jobName].needs, jobName).toEqual(['build', 'prepare-native-cache']) + } + }) + it('includes the paired-runtime web client in the shared E2E build artifact', () => { const buildStep = e2eWorkflow.jobs.build.steps.find((step) => step.name === 'Build E2E outputs') @@ -71,7 +93,7 @@ describe('release E2E dispatch contract', () => { const downloadStep = job.steps.find((step) => step.name === 'Download E2E build output') const runStep = job.steps.find((step) => step.name === runStepName) - expect(job.needs).toBe('build') + expect(job.needs).toEqual(['build', 'prepare-native-cache']) expect(downloadStep.with.name).toBe('e2e-build-out') expect(downloadStep.with.path).toBe('out/') expect(runStep.run).toContain('ORCA_RELAY_PATH="$GITHUB_WORKSPACE/out/relay"') diff --git a/config/scripts/run-ssh-docker-bulk-open-freeze-e2e.mjs b/config/scripts/run-ssh-docker-bulk-open-freeze-e2e.mjs index 36fbbf91500..153f3fb5bc6 100644 --- a/config/scripts/run-ssh-docker-bulk-open-freeze-e2e.mjs +++ b/config/scripts/run-ssh-docker-bulk-open-freeze-e2e.mjs @@ -1,18 +1,17 @@ import { spawnSync } from 'node:child_process' +import { resolvePnpmCliInvocation } from './pnpm-cli-invocation.mjs' const extraArgs = process.argv.slice(2) -const pnpmEntry = process.env.npm_execpath -if (!pnpmEntry) { - throw new Error('npm_execpath is required; run this harness through pnpm') -} +const { command: pnpm, prefixArgs: pnpmPrefix, shell } = resolvePnpmCliInvocation() const env = { ...process.env, ORCA_E2E_SSH_DOCKER: '1' } -const runtime = spawnSync(process.execPath, [pnpmEntry, 'run', 'ensure:electron-runtime'], { +const runtime = spawnSync(pnpm, [...pnpmPrefix, 'run', 'ensure:electron-runtime'], { stdio: 'inherit', - env + env, + shell }) if (runtime.status !== 0) { @@ -20,9 +19,9 @@ if (runtime.status !== 0) { } const result = spawnSync( - process.execPath, + pnpm, [ - pnpmEntry, + ...pnpmPrefix, 'exec', 'playwright', 'test', @@ -36,7 +35,8 @@ const result = spawnSync( ], { stdio: 'inherit', - env + env, + shell } ) diff --git a/config/scripts/verify-telemetry-constants.mjs b/config/scripts/verify-telemetry-constants.mjs index 6b90c89279c..3bdcd8b3ec6 100644 --- a/config/scripts/verify-telemetry-constants.mjs +++ b/config/scripts/verify-telemetry-constants.mjs @@ -34,7 +34,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs' import { join, resolve } from 'node:path' // Why @electron/asar: canonical replacement for the deprecated `asar` package. // It's transitively available via electron-builder (and pnpm's -// `shamefully-hoist=true` in `.npmrc` flattens it into the root +// `shamefullyHoist: true` in `pnpm-workspace.yaml` flattens it into the root // `node_modules`). If electron-builder ever drops it, promote this to a // direct devDependency in package.json. import { extractFile, listPackage } from '@electron/asar' diff --git a/config/scripts/windows-process-tree-gyp-path.test.mjs b/config/scripts/windows-process-tree-gyp-path.test.mjs index e2e650384ec..30770500f42 100644 --- a/config/scripts/windows-process-tree-gyp-path.test.mjs +++ b/config/scripts/windows-process-tree-gyp-path.test.mjs @@ -20,15 +20,22 @@ describe('windows-process-tree node-addon-api gyp path', () => { join(projectDir, 'config/scripts/build-windows-process-tree-relay-addon.mjs'), 'utf8' ) - expect(buildScript).toContain( - "for (const header of ['napi.h', 'napi-inl.h', 'napi-inl.deprecated.h'])" - ) - expect(buildScript).toContain("import { createRequire } from 'node:module'") - expect(buildScript).toContain("import { dirname, join, resolve } from 'node:path'") - expect(buildScript).toContain( - "createRequire(join(PACKAGE_DIR, 'package.json')).resolve('node-addon-api/package.json')" - ) + expect(buildScript).toContain('stageWindowsProcessTreeNodeAddonApiHeaders(PACKAGE_DIR)') expect(buildScript).toContain('Repaired un-applied pnpm patch hunks before build.') + const rebuildHelper = readFileSync( + join(projectDir, 'config/scripts/windows-process-tree-gyp-rebuild.mjs'), + 'utf8' + ) + expect(rebuildHelper).toContain("createRequire(join(packageDir, 'package.json'))") + expect(rebuildHelper).toContain("resolve('node-addon-api/package.json')") + expect(rebuildHelper).toContain("'napi.h'") + expect(rebuildHelper).toContain("'napi-inl.h'") + expect(rebuildHelper).toContain("'napi-inl.deprecated.h'") + const rebuildScript = readFileSync( + join(projectDir, 'config/scripts/rebuild-native-deps.mjs'), + 'utf8' + ) + expect(rebuildScript).toContain('stageWindowsProcessTreeNodeAddonApiHeaders()') }) it('resolves node_addon_api.gyp to a real file from the package directory', () => { diff --git a/config/scripts/windows-process-tree-gyp-rebuild.mjs b/config/scripts/windows-process-tree-gyp-rebuild.mjs index 06ffcb3dfb1..c815407d6d0 100644 --- a/config/scripts/windows-process-tree-gyp-rebuild.mjs +++ b/config/scripts/windows-process-tree-gyp-rebuild.mjs @@ -9,8 +9,9 @@ * hop escapes the store and configure fails with "node_addon_api.gyp not * found" (run 32999886072). */ -import { realpathSync } from 'node:fs' -import { join, resolve } from 'node:path' +import { copyFileSync, mkdirSync, realpathSync } from 'node:fs' +import { createRequire } from 'node:module' +import { dirname, join, resolve } from 'node:path' const ROOT = resolve(import.meta.dirname, '..', '..') @@ -21,6 +22,12 @@ export const WINDOWS_PROCESS_TREE_PACKAGE_DIR = join( 'windows-process-tree' ) +export const WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS = [ + 'napi.h', + 'napi-inl.h', + 'napi-inl.deprecated.h' +] + export function nodeGypRebuildInvocation(arch, packageDir = WINDOWS_PROCESS_TREE_PACKAGE_DIR) { return { args: [ @@ -31,3 +38,18 @@ export function nodeGypRebuildInvocation(arch, packageDir = WINDOWS_PROCESS_TREE cwd: realpathSync(packageDir) } } + +// Patched binding.gyp includes deps/node-addon-api; the tarball does not ship those headers. +export function stageWindowsProcessTreeNodeAddonApiHeaders( + packageDir = WINDOWS_PROCESS_TREE_PACKAGE_DIR +) { + const nodeAddonApiDir = dirname( + createRequire(join(packageDir, 'package.json')).resolve('node-addon-api/package.json') + ) + const stagedHeaderDir = join(packageDir, 'deps', 'node-addon-api') + mkdirSync(stagedHeaderDir, { recursive: true }) + for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) { + copyFileSync(join(nodeAddonApiDir, header), join(stagedHeaderDir, header)) + } + return stagedHeaderDir +} diff --git a/config/scripts/windows-process-tree-gyp-rebuild.test.mjs b/config/scripts/windows-process-tree-gyp-rebuild.test.mjs index a90a92f42bf..f4820e9430a 100644 --- a/config/scripts/windows-process-tree-gyp-rebuild.test.mjs +++ b/config/scripts/windows-process-tree-gyp-rebuild.test.mjs @@ -1,9 +1,20 @@ import { execFileSync } from 'node:child_process' -import { existsSync, realpathSync } from 'node:fs' -import { resolve } from 'node:path' +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync +} from 'node:fs' +import { tmpdir } from 'node:os' +import { join, resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { nodeGypRebuildInvocation, + stageWindowsProcessTreeNodeAddonApiHeaders, + WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS, WINDOWS_PROCESS_TREE_PACKAGE_DIR } from './windows-process-tree-gyp-rebuild.mjs' @@ -26,4 +37,25 @@ describe('windows-process-tree node-gyp rebuild', () => { expect(args).toContain('rebuild') expect(args).toContain('--arch=arm64') }) + + it('copies node-addon-api headers into the patched include dir', () => { + const packageDir = mkdtempSync(join(tmpdir(), 'orca-windows-process-tree-headers-')) + try { + const nodeAddonApiDir = join(packageDir, 'node_modules', 'node-addon-api') + mkdirSync(nodeAddonApiDir, { recursive: true }) + writeFileSync(join(packageDir, 'package.json'), '{"dependencies":{"node-addon-api":"*"}}\n') + writeFileSync(join(nodeAddonApiDir, 'package.json'), '{"name":"node-addon-api"}\n') + for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) { + writeFileSync(join(nodeAddonApiDir, header), `// ${header}\n`) + } + + const stagedDir = stageWindowsProcessTreeNodeAddonApiHeaders(packageDir) + expect(stagedDir).toBe(join(packageDir, 'deps', 'node-addon-api')) + for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) { + expect(readFileSync(join(stagedDir, header), 'utf8')).toBe(`// ${header}\n`) + } + } finally { + rmSync(packageDir, { recursive: true, force: true }) + } + }) }) diff --git a/config/scripts/windows-process-tree-patch-contract.test.mjs b/config/scripts/windows-process-tree-patch-contract.test.mjs index f9c1c90c91a..03b66a9c976 100644 --- a/config/scripts/windows-process-tree-patch-contract.test.mjs +++ b/config/scripts/windows-process-tree-patch-contract.test.mjs @@ -1,6 +1,7 @@ import { createHash } from 'node:crypto' import { readFileSync } from 'node:fs' import { join, resolve } from 'node:path' +import { parseAllDocuments } from 'yaml' import { describe, expect, it } from 'vitest' const projectDir = resolve(import.meta.dirname, '../..') @@ -16,7 +17,9 @@ describe('Windows process-tree patch contract', () => { const patchHash = createHash('sha256') .update(patchBytes.toString('utf8').replaceAll('\r\n', '\n')) .digest('hex') - const lockfile = readFileSync(join(projectDir, 'pnpm-lock.yaml'), 'utf8') - expect(lockfile).toContain(`hash: ${patchHash}`) + const lockfile = parseAllDocuments(readFileSync(join(projectDir, 'pnpm-lock.yaml'), 'utf8')) + .map((document) => document.toJS()) + .find((document) => document.patchedDependencies) + expect(lockfile.patchedDependencies['@vscode/windows-process-tree@0.8.0']).toBe(patchHash) }) }) diff --git a/config/tsconfig.cli.json b/config/tsconfig.cli.json index cec4e80cff5..439a465dc3e 100644 --- a/config/tsconfig.cli.json +++ b/config/tsconfig.cli.json @@ -38,11 +38,24 @@ "../src/main/codex/codex-config-settings-removal.ts", "../src/main/codex/codex-config-settings-upsert.ts", "../src/main/codex/codex-home-paths.ts", + "../src/main/codex/codex-hook-definition.ts", "../src/main/codex/codex-managed-home-resource-copy-marker.ts", "../src/main/codex/codex-managed-trust-grant-plan.ts", "../src/main/codex/codex-path-observation.ts", "../src/main/codex/codex-hook-identity.ts", + "../src/main/codex/codex-hook-legacy-cleanup.ts", + "../src/main/codex/codex-hook-local-install.ts", + "../src/main/codex/codex-hook-local-maintenance.ts", + "../src/main/codex/codex-hook-remote-install.ts", + "../src/main/codex/codex-hook-script.ts", + "../src/main/codex/codex-hook-service-implementation.ts", + "../src/main/codex/codex-hook-status.ts", + "../src/main/codex/codex-hook-system-trust.ts", + "../src/main/codex/codex-hook-trust-cleanup.ts", "../src/main/codex/codex-hook-trust-grant.ts", + "../src/main/codex/codex-hook-trust-queue.ts", + "../src/main/codex/codex-hook-user-mirroring.ts", + "../src/main/codex/codex-hook-wsl-runtime.ts", "../src/main/codex/codex-managed-trust-reconciliation.ts", "../src/main/codex/codex-process-exit-deadline.ts", "../src/main/codex/codex-state-db.ts", diff --git a/docs/assets/readme-downloads.svg b/docs/assets/readme-downloads.svg index 17c8d9e6926..90293d0a7ea 100644 --- a/docs/assets/readme-downloads.svg +++ b/docs/assets/readme-downloads.svg @@ -1,5 +1,5 @@ - - downloads: 32m + + downloads: 33m @@ -15,7 +15,7 @@ downloads downloads - 32m - 32m + 33m + 33m diff --git a/docs/reference/remote-wire-compatibility.md b/docs/reference/remote-wire-compatibility.md index 423149950ce..1fceb67d5d5 100644 --- a/docs/reference/remote-wire-compatibility.md +++ b/docs/reference/remote-wire-compatibility.md @@ -95,16 +95,51 @@ negotiated capabilities differ from the contract. Adding an optional field keeps green (Rule 1); making a client depend on that field turns the new-client/old-host pairing red. +### Never write down what the old side has + +The baseline is whichever release tag is newest, so it moves on every cut. An +expectation of the form "the old side does not have X" — a `not.toHaveProperty`, a +`not.toContain`, a hard-coded field list — stops being true the first time a release +ships X. The suite then reddens on whatever pull request is in flight, with no code +change anywhere, and the job trains people to ignore it. That is worse than no test, +because a rolling baseline eventually contains every additive field the wire has, and +adding one is the sanctioned way to evolve it. + +Derive the expectation from the baseline that was actually checked out: + +- for a published frame, pair each build against a client of its own version and + compare the skewed pairing against that same-version reference, so the expectation + is whatever that build publishes today (`publishedFieldNames` in + `tests/e2e/cross-version-wire/published-field-shape.ts`); +- for a negotiated surface, read the old build's advertised capabilities and + registered method names from its checkout, and assert they agree with each other + rather than asserting the old build lacks them; +- for a "client too old to know X", derive that client's advertised list by removing + X from the baseline's own list, so the gate stays exercised after X ships. + +Name the direction in the assertion. `new client against old server` and `old client +against new server` fail for different reasons, and the host is the only side that +authors a published frame — the terminal `terminalOwner` false positive on 2026-08-29 +was misread as a new client sending an unknown field when the old server was +publishing it. Two things are still safe to state literally: the current build's own +contract, and an invariant that holds for every version. + +Pinning a legacy ref is the fallback when a contract genuinely needs a release from +before a feature shipped, as `cross-version-browser-placement.unit.test.ts` does with +`LEGACY_BROWSER_PLACEMENT_RELEASE_REF`. It does not rot on a cut, but it is +hand-maintained, so prefer deriving. + `tests/e2e/cross-version-wire/cross-version-agent-session-wire.unit.test.ts` pairs the same two builds over the structured `agentSession.*` surface. Because a released build cannot name a capability string its own source never contains, the old side's advertised list and registered method names are read from the extracted checkout rather than hand-written. It covers the three skews that surface can fail on: -- an old client — advertising only what the baseline build defines — is told the whole - surface does not exist and reaches no host method; -- a new client against the old dispatcher gets `method_not_found` on every method, and - can see the absence during negotiation instead of by calling; +- an old client — advertising the baseline's list minus this capability — is told the + whole surface does not exist and reaches no host method; +- a new client against the old dispatcher always gets an answer rather than silence, + and `method_not_found` for every method that release does not register, so the + absence is visible during negotiation instead of by calling; - a cursor survives a host restart: the client's fence is refused as stale with the live one attached, and resuming from the held cursor replays only what it missed. diff --git a/docs/reference/windows-process-enumeration.md b/docs/reference/windows-process-enumeration.md index 4b8acd87aae..ef1faf5237c 100644 --- a/docs/reference/windows-process-enumeration.md +++ b/docs/reference/windows-process-enumeration.md @@ -206,7 +206,7 @@ The addon is Windows-only, so it follows the same contract as `config/scripts/package-electron-runtime-contract.test.mjs`): - an `optionalDependency`, so a macOS/Linux install tolerates its absence; -- **not** in `pnpm.onlyBuiltDependencies` — pnpm installs optional dependencies +- **not** enabled in `allowBuilds` in `pnpm-workspace.yaml` — pnpm installs optional dependencies on every host, and macOS/Linux must never run `node-gyp` for it; - listed in the win32 branch of `rebuild-native-deps.mjs` and `ensure-native-runtime.mjs`; diff --git a/mobile/.npmrc b/mobile/.npmrc deleted file mode 100644 index d7913f44df7..00000000000 --- a/mobile/.npmrc +++ /dev/null @@ -1 +0,0 @@ -minimum-release-age=4320 diff --git a/mobile/.oxlintrc.json b/mobile/.oxlintrc.json index f3338fc3616..703a9dfda62 100644 --- a/mobile/.oxlintrc.json +++ b/mobile/.oxlintrc.json @@ -45,30 +45,12 @@ "max-lines": ["error", { "max": 2152, "skipBlankLines": true, "skipComments": true }] } }, - { - "files": ["app/h/*/index.tsx"], - "rules": { - "max-lines": ["error", { "max": 1603, "skipBlankLines": true, "skipComments": true }] - } - }, - { - "files": ["src/browser/MobileBrowserPane.tsx"], - "rules": { - "max-lines": ["error", { "max": 1594, "skipBlankLines": true, "skipComments": true }] - } - }, { "files": ["app/index.tsx"], "rules": { "max-lines": ["error", { "max": 1422, "skipBlankLines": true, "skipComments": true }] } }, - { - "files": ["src/components/NewWorktreeModal.tsx"], - "rules": { - "max-lines": ["error", { "max": 1263, "skipBlankLines": true, "skipComments": true }] - } - }, { "files": ["src/transport/rpc-client.ts"], "rules": { @@ -81,12 +63,6 @@ "max-lines": ["error", { "max": 407, "skipBlankLines": true, "skipComments": true }] } }, - { - "files": ["app/troubleshoot.tsx"], - "rules": { - "max-lines": ["error", { "max": 436, "skipBlankLines": true, "skipComments": true }] - } - }, { "files": ["app/h/*/files/*.tsx"], "rules": { diff --git a/mobile/app/h/[hostId]/index.tsx b/mobile/app/h/[hostId]/index.tsx index ed26d3dd5cd..7563f7c50dc 100644 --- a/mobile/app/h/[hostId]/index.tsx +++ b/mobile/app/h/[hostId]/index.tsx @@ -1,1410 +1,14 @@ -import { useState, useEffect, useCallback, useMemo, useRef } from 'react' -import { View, Text, SectionList, Pressable, Alert, RefreshControl } from 'react-native' -import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' -import { useFocusEffect, useLocalSearchParams, usePathname, useRouter } from 'expo-router' -import { - Search, - X, - Pin, - List, - SlidersHorizontal, - Layers, - ChevronDown, - ChevronRight, - ChevronLeft, - Plus, - Moon, - Filter, - Check, - UserCircle, - PanelLeftClose, - SquareTerminal -} from 'lucide-react-native' -import type { RpcClient } from '../../../src/transport/rpc-client' -import { loadHosts, updateLastConnected } from '../../../src/transport/host-store' -import { removeHostAndCloseClient } from '../../../src/transport/host-removal-lifecycle' -import { - useHostClient, - useForgetHostClient, - useForceReconnect -} from '../../../src/transport/client-context' -import { useWorktreeResync } from '../../../src/transport/use-worktree-resync' -import { startHostWorktreeRefresh } from '../../../src/worktree/host-worktree-refresh' -import { - applyWorktreeRowDisplayState, - clearConfirmedActiveWorktreeIdentity, - getWorktreeRowIdentity, - removeWorktreeRow, - retainLiveSleptWorktreeIdentities -} from '../../../src/worktree/worktree-host-row-identity' -import { - useLastConnectedAt, - useRelayRecoveryStatus, - useReconnectAttempt -} from '../../../src/transport/client-context-connection-metrics' -import { - classifyConnection, - type ConnectionVerdict -} from '../../../src/transport/connection-health' -import type { RpcSuccess } from '../../../src/transport/types' -import { StatusDot } from '../../../src/components/StatusDot' -import { NewWorktreeModalController } from '../../../src/components/NewWorktreeModalController' -import { NewWorkspaceFab, FAB_SIZE } from '../../../src/components/NewWorkspaceFab' -import { MobileRepoIcon } from '../../../src/components/MobileRepoIcon' -import { WorktreeListRow } from '../../../src/components/WorktreeListRow' -import { useNow } from '../../../src/hooks/use-now' -import { useActiveWorktreeScroll } from '../../../src/hooks/use-active-worktree-scroll' -import type { RepoIcon } from '../../../../src/shared/repo-icon' -import { PickerModal } from '../../../src/components/PickerModal' -import { ActionSheetContent } from '../../../src/components/ActionSheetModal' -import { buildWorktreeNavigationActions } from '../../../src/agent-history/worktree-navigation-actions' -import { floatingWorkspaceSessionPath } from '../../../src/session/floating-workspace' -import { ConfirmModal } from '../../../src/components/ConfirmModal' -import { BottomDrawer } from '../../../src/components/BottomDrawer' -import { useHostProtocolGates } from '../../../src/components/HostProtocolGate' -import { AuthFailedBanner } from '../../../src/components/AuthFailedBanner' -import { HostDiagnosticsLink } from '../../../src/components/HostDiagnosticsLink' -import { HostRouteNoticeBanner } from '../../../src/components/HostRouteNoticeBanner' -import { visibleHostRouteNotice } from '../../../src/host-route-notice' -import { MobileSearchField } from '../../../src/components/MobileSearchField' import { WorkspaceDetailPlaceholder } from '../../../src/components/WorkspaceDetailPlaceholder' -import { getCachedWorktrees, setCachedWorktrees } from '../../../src/cache/worktree-cache' -import { setCachedRepos } from '../../../src/cache/repo-cache' -import { colors, spacing } from '../../../src/theme/mobile-theme' +import { HostScreenView } from '../../../src/host-screen/host-screen-view' +import { + type HostScreenProps, + useHostScreenController +} from '../../../src/host-screen/use-host-screen-controller' import { useResponsiveLayout } from '../../../src/layout/responsive-layout' -import { hostScreenStyles as styles } from '../../../src/host-screen/host-screen-styles' -import { leaveHostRoute } from '../../../src/host-route-exit' -import { loadPinnedIds, savePinnedIds } from '../../../src/storage/preferences' -import { - createInitialHostRouteActionState, - hostNewWorktreeSessionRoute, - resolveHostRouteActionState, - setHostRouteNewWorktreeVisible -} from '../../../src/host-route-action-state' -import { - applyDesktopViewSettings, - buildWorkspaceViewSettingsUpdate, - type MobileGroupMode, - type MobileSortMode, - type MobileViewState, - type WorkspaceViewSettings -} from '../../../src/worktree/workspace-view-settings' -import { - getWorktreeStatus, - isWorktreePinned, - type FilterState, - type Worktree -} from '../../../src/worktree/workspace-list-sections' -import { useWorkspaceSections } from '../../../src/worktree/use-workspace-sections' -import { getMobileWorkspaceLineageGroupKey } from '../../../src/worktree/mobile-workspace-lineage' -import { areWorktreeListsEqual } from '../../../src/worktree/worktree-list-snapshot' -import { WorktreeCatalogSnapshotClient } from '../../../src/worktree/worktree-catalog-snapshot-client' -import { HostWorkspaceListStates } from '../../../src/worktree/host-workspace-list-states' -import { repoColor } from '../../../src/worktree/repo-color' -import { - WORKSPACE_GROUP_OPTIONS as GROUP_OPTIONS, - WORKSPACE_SORT_OPTIONS as SORT_OPTIONS -} from '../../../src/worktree/workspace-list-picker-options' -import type { RepoSummary } from '../../../src/worktree/host-worktree-rpc-types' -import type { WorkspaceStatusDefinition } from '../../../../src/shared/worktree/types' -import { DEFAULT_MOBILE_WORKSPACE_STATUSES } from '../../../src/worktree/mobile-workspace-statuses' -function isErrorVerdict(v: ConnectionVerdict): boolean { - return v.kind === 'warning' || v.kind === 'unreachable' || v.kind === 'auth-failed' -} - -const REPO_METADATA_REFRESH_MS = 60_000 - -type HostScreenProps = { - // When true, rendered as the persistent tablet sidebar by the host layout, not as its own routed screen. - embedded?: boolean - // Route params aren't in scope when rendered from the layout, so the caller passes these explicitly. - hostId?: string - action?: string - onHideSidebar?: () => void -} - -export function HostScreen({ - embedded = false, - hostId: hostIdProp, - action: actionProp, - onHideSidebar -}: HostScreenProps = {}) { - const params = useLocalSearchParams<{ hostId: string; action?: string; notice?: string }>() - const hostId = hostIdProp ?? params.hostId - const action = actionProp ?? params.action - const [dismissedNotice, setDismissedNotice] = useState(null) - const noticeParam = params.notice?.trim() - const routeNotice = visibleHostRouteNotice(embedded, noticeParam, dismissedNotice) - const router = useRouter() - const pathname = usePathname() - const insets = useSafeAreaInsets() - // Why: cap and center the list on wide/tablet canvases; on phones isWideLayout is false so it stays edge-to-edge. - const { isWideLayout, contentMaxWidth } = useResponsiveLayout() - const [initialCache] = useState(() => - hostId ? (getCachedWorktrees(hostId) as Worktree[] | null) : null - ) - // Shared client per host owned by RpcClientProvider. See docs/mobile-shared-client-per-host.md. - const { client, state: connState } = useHostClient(hostId) - const reconnectAttempts = useReconnectAttempt(hostId) - const lastConnectedAt = useLastConnectedAt(hostId) - const relayRecovery = useRelayRecoveryStatus(hostId) - const clientRef = useRef(null) - const fetchWorktreesInFlightRef = useRef(false) - // Why: useRef, not useMemo — React may discard memoized values, which would silently - // reset the snapshot token this object exists to own. - const worktreeCatalogRef = useRef(new WorktreeCatalogSnapshotClient()) - const fetchRepoMetadataInFlightRef = useRef(new WeakSet()) - const fetchRepoMetadataPendingRef = useRef(new WeakSet()) - const repoMetadataFetchedAtRef = useRef(0) - const newWorktreeModalRef = useRef<{ open: () => void }>(null) - const newWorktreeModalVisibleRef = useRef(false) - const forgetHostClient = useForgetHostClient() - const forceReconnectHost = useForceReconnect() - const [worktrees, setWorktrees] = useState(initialCache ?? []) - const [worktreesLoaded, setWorktreesLoaded] = useState(initialCache != null) - // Why (STA-3123): error code of the last failed worktree.ps, so a broken catalog - // path renders as a failure instead of an empty host. Cleared on the next success. - const [catalogError, setCatalogError] = useState(null) - // Why: track the locally-opened worktree so the active-row highlight moves instantly instead of waiting for the next poll. - const [optimisticActiveWorktreeIdentity, setOptimisticActiveWorktreeIdentity] = useState< - string | null - >(null) - // One tick drives every visible agent row's relative timestamp. - const now = useNow(30_000) - const [repoColorsByName, setRepoColorsByName] = useState>(new Map()) - const [repoIconsByName, setRepoIconsByName] = useState>(new Map()) - const [hostName, setHostName] = useState('') - const [error, setError] = useState('') - const [lastKnownWorktrees, setLastKnownWorktrees] = useState(initialCache ?? []) - const [search, setSearch] = useState('') - const [showSearch, setShowSearch] = useState(false) - const [sortMode, setSortMode] = useState('recent') - const [filters, setFilters] = useState({ - filterRepoIds: new Set(), - hideSleeping: false, - hideDefaultBranch: false, - alwaysShowDefaultBranch: true - }) - const [groupMode, setGroupMode] = useState('repo') - const [workspaceStatuses, setWorkspaceStatuses] = useState( - DEFAULT_MOBILE_WORKSPACE_STATUSES - ) - // displayName → repo id: filters key on repo id, but section headers/rows key on displayName, so bridge the two. - const [repoIdsByName, setRepoIdsByName] = useState>(new Map()) - const [showSortPicker, setShowSortPicker] = useState(false) - const [showGroupPicker, setShowGroupPicker] = useState(false) - const [showFilterModal, setShowFilterModal] = useState(false) - const [actionTarget, setActionTarget] = useState(null) - const { hostCapabilities, floatingWorkspaceEnabled } = useHostProtocolGates() - const [confirmDelete, setConfirmDelete] = useState(null) - const [confirmRemoveHost, setConfirmRemoveHost] = useState(false) - const [routeActionState, setRouteActionState] = useState(() => - createInitialHostRouteActionState(action) - ) - const [sleptIds, setSleptIds] = useState>(new Set()) - - const leaveHost = useCallback(() => { - leaveHostRoute(router) - }, [router]) - const [pinnedIds, setPinnedIds] = useState>(new Set()) - const [collapsedGroups, setCollapsedGroups] = useState>(new Set()) - // Why: ref so the ui.get merge and ui.set writes read the latest values without re-creating callbacks on every state change. - const viewStateRef = useRef({ - groupMode: 'repo', - sortMode: 'recent', - hideSleeping: false, - hideDefaultBranch: false, - alwaysShowDefaultBranch: true, - filterRepoIds: [], - collapsedGroups: [], - workspaceStatuses: DEFAULT_MOBILE_WORKSPACE_STATUSES - }) - - useEffect(() => { - viewStateRef.current = { - groupMode, - sortMode, - hideSleeping: filters.hideSleeping, - hideDefaultBranch: filters.hideDefaultBranch, - alwaysShowDefaultBranch: filters.alwaysShowDefaultBranch !== false, - filterRepoIds: [...filters.filterRepoIds], - collapsedGroups: [...collapsedGroups], - workspaceStatuses - } - }, [groupMode, sortMode, filters, collapsedGroups, workspaceStatuses]) - - // Apply a MobileViewState onto the individual states and the snapshot ref in one shot. - const applyViewState = useCallback((next: MobileViewState) => { - viewStateRef.current = next - setGroupMode(next.groupMode) - setSortMode(next.sortMode) - setWorkspaceStatuses(next.workspaceStatuses) - setCollapsedGroups(new Set(next.collapsedGroups)) - setFilters({ - filterRepoIds: new Set(next.filterRepoIds), - hideSleeping: next.hideSleeping, - hideDefaultBranch: next.hideDefaultBranch, - alwaysShowDefaultBranch: next.alwaysShowDefaultBranch - }) - }, []) - - // Apply the change locally, then patch the desktop's shared store (ui.set) so both apps stay in sync. - const persistViewSettings = useCallback( - (patch: Partial) => { - const next: MobileViewState = { ...viewStateRef.current, ...patch } - applyViewState(next) - if (!client) { - return - } - // Send only the touched fields: the host merges partial updates, so a stale - // mirror can no longer revert sibling settings another client just changed - // (STA-5781; supersedes the #8873 whole-payload special case). - const payload: WorkspaceViewSettings = buildWorkspaceViewSettingsUpdate(patch, next) - if (Object.keys(payload).length === 0) { - return - } - void client.sendRequest('ui.set', payload).catch(() => { - // Best-effort: view settings are a convenience preference. - }) - }, - [client, applyViewState] - ) - - const openNewWorktreeModal = useCallback(() => { - const modal = newWorktreeModalRef.current - if (!modal) { - return - } - newWorktreeModalVisibleRef.current = true - modal.open() - }, []) - - const resolvedRouteActionState = resolveHostRouteActionState(routeActionState, action) - // Why: resolve `action=newWorktree` before commit, but don't reopen after the user closes while the URL persists. - if (resolvedRouteActionState !== routeActionState) { - setRouteActionState(resolvedRouteActionState) - } - const showNewWorktree = resolvedRouteActionState.showNewWorktree - const setShowNewWorktreeVisible = useCallback((visible: boolean) => { - setRouteActionState((current) => setHostRouteNewWorktreeVisible(current, visible)) - }, []) - - // Load persisted pins from local cache; view settings are no longer local (they sync via ui.get). - useEffect(() => { - if (!hostId) { - return - } - let stale = false - void (async () => { - const pins = await loadPinnedIds(hostId) - if (stale) { - return - } - setPinnedIds(pins) - })() - return () => { - stale = true - } - }, [hostId]) - - // Merge the desktop's shared view settings (PersistedUIState) onto local state so desktop changes appear here. - const syncViewSettingsFromDesktop = useCallback(async () => { - if (!client || connState !== 'connected') { - return - } - const requestClient = client - const requestHostId = hostId - try { - const response = await requestClient.sendRequest('ui.get') - if (clientRef.current !== requestClient || hostId !== requestHostId || !response.ok) { - return - } - const ui = ((response as RpcSuccess).result as { ui?: WorkspaceViewSettings }).ui - if (!ui) { - return - } - applyViewState(applyDesktopViewSettings(viewStateRef.current, ui)) - } catch { - // Transient transport failure; retry on the next focus/connect. - } - }, [client, connState, hostId, applyViewState]) - - // Why: mirror client into a ref so imperative call sites read it without re-subscribing. - useEffect(() => { - clientRef.current = client - }, [client]) - - useEffect(() => { - setHostName('') - setError('') - setRepoColorsByName(new Map()) - setRepoIconsByName(new Map()) - repoMetadataFetchedAtRef.current = 0 - // Why: useState initializer runs only on first mount, so re-seed the cache when Expo Router reuses this screen for a new hostId. - const freshCache = hostId ? (getCachedWorktrees(hostId) as Worktree[] | null) : null - setCatalogError(null) - if (freshCache) { - setWorktrees(freshCache) - setLastKnownWorktrees(freshCache) - setWorktreesLoaded(true) - } else { - setWorktreesLoaded(false) - setWorktrees([]) - setLastKnownWorktrees([]) - } - if (!hostId) { - return - } - let stale = false - void loadHosts().then((hosts) => { - if (stale) { - return - } - const host = hosts.find((h) => h.id === hostId) - if (!host) { - setError('Host not found') - return - } - setHostName(host.name) - void updateLastConnected(host.id) - }) - return () => { - stale = true - } - }, [hostId]) - - const fetchRepoMetadata = useCallback( - async (options: { force?: boolean; queueIfInFlight?: boolean } = {}) => { - if (!client || connState !== 'connected' || !hostId) { - return - } - if (fetchRepoMetadataInFlightRef.current.has(client)) { - if (options.queueIfInFlight) { - fetchRepoMetadataPendingRef.current.add(client) - } - return - } - const now = Date.now() - if (!options.force && now - repoMetadataFetchedAtRef.current < REPO_METADATA_REFRESH_MS) { - return - } - fetchRepoMetadataInFlightRef.current.add(client) - const requestClient = client, - requestHostId = hostId - try { - do { - fetchRepoMetadataPendingRef.current.delete(requestClient) - const repoResponse = await requestClient.sendRequest('repo.list') - if (clientRef.current !== requestClient || hostId !== requestHostId || !repoResponse.ok) { - return - } - const repoResult = (repoResponse as RpcSuccess).result as { repos: RepoSummary[] } - repoMetadataFetchedAtRef.current = Date.now() - setCachedRepos(requestHostId, repoResult.repos) - setRepoColorsByName( - new Map( - repoResult.repos.map((repo) => [ - repo.displayName, - repo.badgeColor || repoColor(repo.displayName) - ]) - ) - ) - setRepoIconsByName( - new Map( - repoResult.repos.flatMap((repo) => - repo.repoIcon ? [[repo.displayName, repo.repoIcon] as const] : [] - ) - ) - ) - setRepoIdsByName(new Map(repoResult.repos.map((repo) => [repo.displayName, repo.id]))) - } while (fetchRepoMetadataPendingRef.current.has(requestClient)) - } catch { - // Repo metadata is decorative; the next refresh can retry. - } finally { - fetchRepoMetadataInFlightRef.current.delete(requestClient) - } - }, - [client, connState, hostId] - ) - - const fetchWorktrees = useCallback( - async (options: { allowDuringModal?: boolean } = {}) => { - if (!client || connState !== 'connected') { - return - } - if (!options.allowDuringModal && newWorktreeModalVisibleRef.current) { - return - } - // Why: prevent slow remote hosts from stacking overlapping worktree.ps requests during polling. - if (fetchWorktreesInFlightRef.current) { - return - } - fetchWorktreesInFlightRef.current = true - const requestClient = client - const requestHostId = hostId - - try { - const fetched = await worktreeCatalogRef.current.fetch(requestClient, requestHostId) - if (clientRef.current !== requestClient || hostId !== requestHostId) { - return - } - if (!options.allowDuringModal && newWorktreeModalVisibleRef.current) { - return - } - // Why (STA-3123): a failed catalog request must not pass for "0 worktrees"; - // surface it so a broken remote host is diagnosable instead of looking empty. - if (fetched.kind === 'request_failed') { - setCatalogError(fetched.code) - return - } - if (fetched.pending.admission.kind === 'invalid') { - setCatalogError('invalid_response') - } - // Why: unchanged responses still yield the confirmed rows, so every poll reasserts - // host truth over optimistic local edits regardless of payload size. - const confirmed = worktreeCatalogRef.current.admit(fetched.pending) - if (confirmed) { - setCatalogError(null) - // Why: reuse the existing array on identical snapshots to keep SectionList/sort rebuilds off the tap path. - setWorktrees((current) => - areWorktreeListsEqual(current, confirmed) ? current : confirmed - ) - setLastKnownWorktrees((current) => - areWorktreeListsEqual(current, confirmed) ? current : confirmed - ) - setWorktreesLoaded(true) - // Why (#8498): overwrite the home-written cache with the confirmed snapshot so a reconnect/remount can't serve a stale list. - if (hostId) { - setCachedWorktrees(hostId, confirmed, { proven: true }) - } - // Drop the optimistic active override once the host reports it active, so later desktop changes win. - setOptimisticActiveWorktreeIdentity((pending) => - clearConfirmedActiveWorktreeIdentity(pending, confirmed) - ) - - // Clear optimistic sleep overrides once the server confirms inactive (liveTerminalCount === 0). - setSleptIds((prev) => retainLiveSleptWorktreeIdentities(prev, confirmed)) - - // Sync pin state from server so desktop-initiated pins reflect without relying on stale AsyncStorage. - const serverPinned = new Set(confirmed.filter((w) => w.isPinned).map((w) => w.worktreeId)) - setPinnedIds((prev) => { - if (serverPinned.size === prev.size && [...serverPinned].every((id) => prev.has(id))) { - return prev - } - if (hostId) { - void savePinnedIds(hostId, serverPinned) - } - return serverPinned - }) - } - } catch { - // Will retry on reconnect - if (clientRef.current === requestClient && hostId === requestHostId) { - setCatalogError('network_error') - } - } finally { - fetchWorktreesInFlightRef.current = false - } - }, - [client, connState, hostId] - ) - - useFocusEffect( - useCallback(() => { - // Why: focus nudges reconnect and probes a possibly half-open socket; empty deps fire per focus, not per state flip (which defeats backoff). - // 'focus' keeps a healthy relay green — probe, never suspend (S2 grey blink). - clientRef.current?.notifyForeground('focus') - }, []) - ) - - const startWorktreeRefresh = useCallback(() => { - if (!client || connState !== 'connected') { - return - } - void syncViewSettingsFromDesktop() - return startHostWorktreeRefresh({ client, fetchWorktrees, fetchRepoMetadata }) - }, [client, connState, fetchWorktrees, fetchRepoMetadata, syncViewSettingsFromDesktop]) - - useFocusEffect( - useCallback(() => { - // The embedded sidebar isn't a routed screen (focus never fires); it refreshes via the mount effect below. - if (!embedded) { - return startWorktreeRefresh() - } - }, [embedded, startWorktreeRefresh]) - ) - - // Why: the embedded sidebar is never the focused route, so wire its refresh lifecycle from a mount effect. - useEffect(() => { - if (embedded) { - return startWorktreeRefresh() - } - }, [embedded, startWorktreeRefresh]) - - // Why (#8498): steady-state polls miss the transition INTO 'connected' after background/sleep, when the cache is stalest. - const { refreshing, onRefresh } = useWorktreeResync({ - client, - connState, - fetchWorktrees, - fetchRepoMetadata - }) - - const updateLocalPins = useCallback( - (worktreeId: string, pinned: boolean) => { - setPinnedIds((prev) => { - const next = new Set(prev) - if (pinned) { - next.add(worktreeId) - } else { - next.delete(worktreeId) - } - if (hostId) { - void savePinnedIds(hostId, next) - } - return next - }) - }, - [hostId] - ) - - const togglePin = useCallback( - (worktreeId: string) => { - const worktree = worktrees.find((w) => w.worktreeId === worktreeId) - const currentlyPinned = worktree - ? isWorktreePinned(worktree, pinnedIds) - : pinnedIds.has(worktreeId) - const newPinned = !currentlyPinned - - setWorktrees((prev) => - prev.map((w) => (w.worktreeId === worktreeId ? { ...w, isPinned: newPinned } : w)) - ) - setLastKnownWorktrees((prev) => - prev.map((w) => (w.worktreeId === worktreeId ? { ...w, isPinned: newPinned } : w)) - ) - - updateLocalPins(worktreeId, newPinned) - - if (client) { - client - .sendRequest('worktree.set', { - worktree: `id:${worktreeId}`, - isPinned: newPinned - }) - .catch(() => {}) - } - }, - [client, worktrees, pinnedIds, updateLocalPins] - ) - - const handleDeleteWorktree = useCallback( - async (item: Worktree) => { - if (!client) { - return - } - - const removeFromList = (list: Worktree[]) => removeWorktreeRow(list, item) - setWorktrees(removeFromList) - setLastKnownWorktrees(removeFromList) - - try { - const response = await client.sendRequest('worktree.rm', { - worktree: `id:${item.worktreeId}`, - force: true - }) - if (!response.ok) { - setWorktrees((prev) => [...prev, item]) - setLastKnownWorktrees((prev) => [...prev, item]) - } - void fetchWorktrees() - } catch { - setWorktrees((prev) => [...prev, item]) - setLastKnownWorktrees((prev) => [...prev, item]) - } - }, - [client, fetchWorktrees] - ) - - const handleRemoveHost = useCallback(async () => { - if (!hostId) { - return - } - try { - await removeHostAndCloseClient(hostId, forgetHostClient) - leaveHost() - } catch { - // Why: removal can fail while still paired; re-open confirm (ConfirmModal closes on confirm). - setConfirmRemoveHost(true) - Alert.alert('Could not remove host', 'Please try again.') - } - }, [hostId, leaveHost, forgetHostClient]) - - const navigateFromHostList = useCallback( - (target: string) => { - if (!embedded) { - router.push(target) - return - } - if (pathname === (target.split('?')[0] ?? target)) { - return - } - if (pathname === `/h/${hostId}`) { - router.push(target) - return - } - router.replace(target) - }, - [embedded, hostId, pathname, router] - ) - - const openWorktreeSession = useCallback( - (item: Worktree) => { - setOptimisticActiveWorktreeIdentity(getWorktreeRowIdentity(item)) - if (client && connState === 'connected') { - void client - .sendRequest('worktree.activate', { - worktree: `id:${item.worktreeId}`, - notifyClients: false, - navigation: 'caller' - }) - .catch(() => null) - } - const target = `/h/${hostId}/session/${encodeURIComponent(item.worktreeId)}?name=${encodeURIComponent(item.displayName || item.repo)}` - navigateFromHostList(target) - }, - [client, connState, hostId, navigateFromHostList] - ) - - const openFloatingWorkspace = useCallback(() => { - // Why: no worktree.activate here — the floating sentinel has no worktree - // record; session.tabs.list hydrates its host-owned tabs on open. - navigateFromHostList(floatingWorkspaceSessionPath(hostId)) - }, [hostId, navigateFromHostList]) - - const handleSortChange = useCallback( - (value: MobileSortMode) => { - persistViewSettings({ sortMode: value }) - }, - [persistViewSettings] - ) - - const toggleHideSleeping = useCallback(() => { - persistViewSettings({ hideSleeping: !viewStateRef.current.hideSleeping }) - }, [persistViewSettings]) - - const toggleHideDefaultBranch = useCallback(() => { - persistViewSettings({ hideDefaultBranch: !viewStateRef.current.hideDefaultBranch }) - }, [persistViewSettings]) - - const toggleRepoFilter = useCallback( - (repoId: string) => { - const next = new Set(viewStateRef.current.filterRepoIds) - if (next.has(repoId)) { - next.delete(repoId) - } else { - next.add(repoId) - } - persistViewSettings({ filterRepoIds: [...next] }) - }, - [persistViewSettings] - ) - - const clearFilters = useCallback(() => { - persistViewSettings({ hideSleeping: false, hideDefaultBranch: false, filterRepoIds: [] }) - }, [persistViewSettings]) - - const activeFilterCount = useMemo(() => { - let count = 0 - if (filters.hideSleeping) { - count++ - } - if (filters.hideDefaultBranch) { - count++ - } - count += filters.filterRepoIds.size - return count - }, [filters]) - const selectedSortLabel = - SORT_OPTIONS.find((option) => option.value === sortMode)?.label ?? 'Recent' - - const handleGroupChange = useCallback( - (value: MobileGroupMode) => { - persistViewSettings({ groupMode: value }) - }, - [persistViewSettings] - ) - - const displayWorktrees = useMemo(() => { - // Why: live `worktrees` is authoritative only while connected; under the amber - // mount default, connecting/handshaking must keep the pre-reconnect list too. - const base = connState === 'connected' ? worktrees : lastKnownWorktrees - return applyWorktreeRowDisplayState(base, sleptIds, optimisticActiveWorktreeIdentity) - }, [connState, worktrees, lastKnownWorktrees, sleptIds, optimisticActiveWorktreeIdentity]) - - const toggleCollapsed = useCallback( - (key: string) => { - const next = new Set(viewStateRef.current.collapsedGroups) - if (!next.delete(key)) { - next.add(key) - } - persistViewSettings({ collapsedGroups: [...next] }) - }, - [persistViewSettings] - ) - const toggleWorktreeLineage = useCallback( - (item: Worktree) => toggleCollapsed(getMobileWorkspaceLineageGroupKey(item)), - [toggleCollapsed] - ) - const { sections, rawSections, uniqueRepos, uniqueRepoColors } = useWorkspaceSections({ - displayWorktrees, - sortMode, - filters, - search, - groupMode, - pinnedIds, - repoIdsByName, - repoColorsByName, - collapsedGroups, - workspaceStatuses - }) - const existingWorktreePaths = useMemo(() => worktrees.map((w) => w.path), [worktrees]) - - const { sectionListRef, onScrollToIndexFailed } = useActiveWorktreeScroll(sections) - - const isReadOnly = connState === 'auth-failed' - - if (error) { - return ( - - {error} - - ) - } - - return ( - - - - - - - {(() => { - const headerVerdict = classifyConnection({ - state: connState, - reconnectAttempts, - lastConnectedAt, - ...relayRecovery - }) - return ( - <> - - - - {hostName || 'Host'} - - - {connState !== 'connected' && - (() => { - // Why: auth-failed has its own banner, so suppress the Reconnect button for that verdict. - const verdict = headerVerdict - const isError = isErrorVerdict(verdict) - const showReconnectButton = isError && hostId && verdict.kind !== 'auth-failed' - if (!showReconnectButton) { - return null - } - return ( - void forceReconnectHost(hostId!)} - hitSlop={8} - > - Reconnect - - ) - })()} - - ) - })()} - {!embedded && floatingWorkspaceEnabled ? ( - - - - ) : null} - {embedded && onHideSidebar ? ( - - - - ) : null} - - - {/* Filter/sort/group toolbar */} - {embedded ? ( - - - 0 && styles.filterChipActive - ]} - onPress={() => setShowFilterModal(true)} - accessibilityRole="button" - accessibilityLabel={`Filter workspaces${activeFilterCount > 0 ? `, ${activeFilterCount} active` : ''}`} - > - 0 ? colors.textPrimary : colors.textSecondary} - /> - 0 && styles.filterChipTextActive - ]} - numberOfLines={1} - > - Filter{activeFilterCount > 0 ? ` ${activeFilterCount}` : ''} - - - - setShowSortPicker(true)} - accessibilityRole="button" - accessibilityLabel={`Sort by ${selectedSortLabel}`} - > - - - {selectedSortLabel} - - - - setShowGroupPicker(true)} - accessibilityRole="button" - accessibilityLabel="Group workspaces" - > - - - {groupMode === 'none' - ? 'Group' - : groupMode === 'workspaceStatus' - ? 'Status' - : groupMode === 'repo' - ? 'Repo' - : 'PR'} - - - - - - navigateFromHostList(`/h/${hostId}/accounts`)} - disabled={connState !== 'connected'} - accessibilityRole="button" - accessibilityLabel="Accounts" - > - - - - navigateFromHostList(`/h/${hostId}/tasks`)} - disabled={connState !== 'connected'} - accessibilityRole="button" - accessibilityLabel="Tasks" - > - - - - {floatingWorkspaceEnabled ? ( - - - - ) : null} - - - - - - setShowSearch((s) => !s)} - accessibilityRole="button" - accessibilityLabel={showSearch ? 'Close search' : 'Search workspaces'} - > - {showSearch ? ( - - ) : ( - - )} - - - - ) : ( - - 0 && styles.filterChipActive]} - onPress={() => setShowFilterModal(true)} - > - 0 ? colors.textPrimary : colors.textSecondary} - /> - 0 && styles.filterChipTextActive - ]} - > - Filter{activeFilterCount > 0 ? ` (${activeFilterCount})` : ''} - - - - setShowSortPicker(true)}> - - - {selectedSortLabel} - - - - setShowGroupPicker(true)}> - - - {groupMode === 'none' - ? 'Group' - : groupMode === 'workspaceStatus' - ? 'Status' - : groupMode === 'repo' - ? 'Repo' - : 'PR'} - - - - - - navigateFromHostList(`/h/${hostId}/accounts`)} - disabled={connState !== 'connected'} - > - - - - navigateFromHostList(`/h/${hostId}/tasks`)} - disabled={connState !== 'connected'} - > - - - - setShowSearch((s) => !s)}> - {showSearch ? ( - - ) : ( - - )} - - - )} - - - {/* Auth failed: a latched relay rejection must reach the same re-pair affordance. */} - {(connState === 'auth-failed' || relayRecovery.pairingRejected) && ( - hostId && void forceReconnectHost(hostId)} - onRepair={() => router.push('/pair-scan')} - onRemove={() => setConfirmRemoveHost(true)} - /> - )} - - {connState !== 'connected' && - !relayRecovery.pairingRejected && - reconnectAttempts >= 3 && - hostId ? ( - - router.push({ pathname: '/connection-log', params: { hostId: String(hostId) } }) - } - /> - ) : null} - - {/* Why a bounced route landed here (e.g. the workspace was deleted on the desktop). */} - {routeNotice && ( - setDismissedNotice(noticeParam ?? null)} - /> - )} - - {/* Search bar */} - {showSearch && ( - - - - )} - - - - {sections.length > 0 && ( - w.sectionListKey ?? getWorktreeRowIdentity(w)} - stickySectionHeadersEnabled={false} - // Why: keep the search IME up while tapping clear / scrolling results. - keyboardShouldPersistTaps="handled" - keyboardDismissMode="on-drag" - onScrollToIndexFailed={onScrollToIndexFailed} - // Why: edge-to-edge under the system nav bar; insets.bottom keeps the last row above it. - contentContainerStyle={[ - styles.list, - // Reserve room so the last row stays tappable above the phone's floating "+" (embedded uses the toolbar +). - { paddingBottom: (embedded ? spacing.lg : FAB_SIZE + spacing.xl) + insets.bottom }, - isWideLayout && - !embedded && { maxWidth: contentMaxWidth, width: '100%', alignSelf: 'center' } - ]} - renderSectionHeader={({ section }) => { - if (!section.title) { - return null - } - const isCollapsed = collapsedGroups.has(section.key) - const rawSection = rawSections.find((s) => s.key === section.key) - const count = rawSection?.data.length ?? 0 - const repoSectionColor = - groupMode === 'repo' ? uniqueRepoColors.get(section.title) : null - const repoSectionIcon = groupMode === 'repo' ? repoIconsByName.get(section.title) : null - return ( - toggleCollapsed(section.key)}> - {isCollapsed ? ( - - ) : ( - - )} - {section.icon === 'pin' && ( - - )} - {groupMode === 'repo' ? ( - - - - ) : null} - {section.title} - {count} - - ) - }} - ItemSeparatorComponent={ListSeparator} - // Why (#8498): manual pull-to-refresh forces a fresh snapshot after a stale-cache reconnect. - refreshControl={ - - } - renderItem={({ item }) => ( - - )} - /> - )} - - {/* Floating "new workspace" button — phone only; embedded sidebars keep the toolbar +. */} - {!embedded && ( - - )} - - setShowSortPicker(false)} - /> - - setShowGroupPicker(false)} - /> - - setShowFilterModal(false)}> - - Filter - {activeFilterCount > 0 && ( - - Clear filters - - )} - - - Workspaces - - - Hide sleeping - {filters.hideSleeping && } - - - - Hide default branch - {filters.hideDefaultBranch && } - - - - {uniqueRepos.length > 1 && ( - <> - Repositories - - {uniqueRepos.map((repo, i) => ( - - {i > 0 && } - toggleRepoFilter(repo.id)}> - - - {repo.name} - - {filters.filterRepoIds.has(repo.id) && ( - - )} - - - ))} - - - )} - - - {/* Worktree long-press action sheet (inline confirm to avoid double-Modal lag) */} - { - setConfirmDelete(null) - setActionTarget(null) - }} - > - {confirmDelete ? ( - - - Delete Worktree - - Delete "{confirmDelete.displayName || confirmDelete.repo}" ({confirmDelete.branch})? - - - - [ - styles.confirmBtn, - styles.confirmBtnCancel, - pressed && styles.confirmBtnPressed - ]} - onPress={() => setConfirmDelete(null)} - > - Cancel - - [ - styles.confirmBtn, - styles.confirmBtnDestructive, - pressed && styles.confirmBtnPressed - ]} - onPress={() => { - if (confirmDelete) { - void handleDeleteWorktree(confirmDelete) - } - setConfirmDelete(null) - setActionTarget(null) - }} - > - Delete - - - - ) : ( - setActionTarget(null) - }), - { - label: 'Sleep', - icon: Moon, - onPress: () => { - if (client) { - setSleptIds((prev) => - new Set(prev).add(getWorktreeRowIdentity(actionTarget)) - ) - void client - .sendRequest('worktree.sleep', { - worktree: `id:${actionTarget.worktreeId}` - }) - .catch(() => null) - } - setActionTarget(null) - } - }, - { - label: isWorktreePinned(actionTarget, pinnedIds) ? 'Unpin' : 'Pin', - onPress: () => { - togglePin(actionTarget.worktreeId) - setActionTarget(null) - } - }, - { - label: 'Delete', - destructive: true, - onPress: () => setConfirmDelete(actionTarget) - } - ] - : [] - } - /> - )} - - - {/* Host remove confirmation */} - void handleRemoveHost()} - onCancel={() => setConfirmRemoveHost(false)} - /> - - { - newWorktreeModalVisibleRef.current = visible - }} - onCreated={(worktreeId, worktreeName) => { - void fetchWorktrees({ allowDuringModal: true }) - navigateFromHostList(hostNewWorktreeSessionRoute(hostId, worktreeId, worktreeName)) - }} - onRouteVisibleChange={setShowNewWorktreeVisible} - /> - - ) +export function HostScreen(props: HostScreenProps = {}) { + const controller = useHostScreenController(props) + return } // On wide layouts the sidebar hosts the list, so this route is just the empty detail pane. @@ -1415,7 +19,3 @@ export default function HostWorktreeRoute() { } return } - -function ListSeparator() { - return -} diff --git a/mobile/app/h/[hostId]/session/[worktreeId].tsx b/mobile/app/h/[hostId]/session/[worktreeId].tsx index 0d36fa96020..5978bae2353 100644 --- a/mobile/app/h/[hostId]/session/[worktreeId].tsx +++ b/mobile/app/h/[hostId]/session/[worktreeId].tsx @@ -182,6 +182,7 @@ import { } from '../../../../src/session/mobile-file-syntax' import { getTerminalRecordsFromSessionTabs, + hasConnectedTerminalAbsentFromSessionTabs, mergeTerminalListWithKnownRecords, mergeTerminalRecordsByCurrentOrder, mobileSessionTabsEqual, @@ -245,6 +246,11 @@ import { } from '../../../../src/session/mobile-terminal-prune-decision' import { useMobileNativeChatTerminalStream } from '../../../../src/session/use-mobile-native-chat-terminal-stream' import { subscribeMobileTerminalSafely } from '../../../../src/session/mobile-terminal-stream-subscribe' +import { MobileTerminalInventoryRequest } from '../../../../src/session/mobile-terminal-inventory-request' +import { + useMobileTerminalInventoryRecoveryBridge, + type MobileTerminalInventoryRefreshOptions +} from '../../../../src/session/use-mobile-terminal-inventory-recovery' import { TerminalViewportResubscribeBudget, readTerminalViewportDims, @@ -1277,6 +1283,9 @@ export default function SessionScreen() { ) const unsubscribeTerminalRef = useRef(unsubscribeTerminal) unsubscribeTerminalRef.current = unsubscribeTerminal + const terminalInventoryRecoveryScope = JSON.stringify([hostId, worktreeId]) + const { registerTerminalInventoryRecoveryAction, signalTerminalInventoryRecovery } = + useMobileTerminalInventoryRecoveryBridge(terminalInventoryRecoveryScope) const clearTerminalCache = useCallback(() => { terminalUnsubsRef.current.forEach((unsub) => unsub()) @@ -1379,6 +1388,7 @@ export default function SessionScreen() { diagnostics.firstStreamEvent(handle, seq, data.type) if (data.type === 'end' || data.type === 'error') { unsubscribeTerminalRef.current(handle) + signalTerminalInventoryRecovery() return } if (data.type === 'subscribed') { @@ -1522,7 +1532,10 @@ export default function SessionScreen() { scheduleDelayedAction(() => getTerminalRef(handle)?.resetZoom(), 200) } }, - () => unsubscribeTerminalRef.current(handle) + () => { + unsubscribeTerminalRef.current(handle) + signalTerminalInventoryRecovery() + } ) if (subscribeSeqRef.current.get(handle) === seq) { @@ -1532,7 +1545,14 @@ export default function SessionScreen() { } subscribingHandlesRef.current.delete(handle) }, - [client, getTerminalRef, markNativeChatInputLeaseReady, scheduleDelayedAction, showToast] + [ + client, + getTerminalRef, + markNativeChatInputLeaseReady, + scheduleDelayedAction, + showToast, + signalTerminalInventoryRecovery + ] ) const nativeChatStream = useMobileNativeChatTerminalStream({ @@ -1586,93 +1606,105 @@ export default function SessionScreen() { ) const lastKnownTerminalCountRef = useRef(0) - const fetchTerminalsInFlightRef = useRef(false) + const terminalInventoryRequest = useMemo( + () => new MobileTerminalInventoryRequest(), + [client, hostId, worktreeId] + ) + useEffect(() => { + lastKnownTerminalCountRef.current = 0 + return terminalInventoryRequest.activate() + }, [terminalInventoryRequest]) const fetchTerminals = useCallback( - async (opts: { allowEmptyLoaded?: boolean } = {}) => { + (opts: MobileTerminalInventoryRefreshOptions = {}): Promise => { if (!client) { - return + return Promise.resolve(false) } - if (fetchTerminalsInFlightRef.current) { - return - } - fetchTerminalsInFlightRef.current = true const allowEmptyLoaded = opts.allowEmptyLoaded ?? true - - try { - const response = await client.sendRequest('terminal.list', { - worktree: `id:${worktreeId}`, - includeVisualLayouts: false - }) - if (response.ok) { - const result = (response as RpcSuccess).result as { terminals: Terminal[] } - if (result.terminals.length === 0 && !allowEmptyLoaded) { - return - } - // Why: require two consecutive empties before trusting 0, so transient empty responses don't flash the UI empty. - if (result.terminals.length === 0 && lastKnownTerminalCountRef.current > 0) { - lastKnownTerminalCountRef.current = 0 - return - } - - const liveHandles = new Set(result.terminals.map((terminal) => terminal.handle)) - const pruneContext = { - liveHandles, - showNativeChat: showNativeChatRef.current, - activeHandle: activeHandleRef.current - } - // Why: terminal.list is the lifetime signal; lagging tab snapshots must not erase a user's buffered-mode opt-out. - // Sweep against the retained set, not the raw list: a chat-covered handle - // keeps its subscription across a graph reload, so erasing its live-input - // preference on the same refresh is the erasure this guard exists to stop. - pruneTerminalHandlesFromLiveInput(resolveRetainedTerminalHandles(pruneContext)) - defaultTerminalHandlesToLiveInput([...liveHandles]) - const shouldPrune = createTerminalPrunePredicate(pruneContext) - for (const handle of Array.from(terminalUnsubsRef.current.keys())) { - if (!shouldPrune(handle)) { - continue - } - unsubscribeTerminal(handle) - terminalRefs.current.delete(handle) - initializedHandlesRef.current.delete(handle) - viewportResubscribeBudgetRef.current.forget(handle) - clearTerminalLiveInputDefault(handle) - } - setTerminalKeyboardMetrics((prev) => pruneTerminalKeyboardMetrics(prev, shouldPrune)) - // Why: a chat-covered handle the host reports again refills its rearm budget, - // so an exhausted rearm can't lock the composer until leave-chat. - nativeChatStream.notifyListedHandles(liveHandles) - // Why: same absence-gated refill for the viewport-fit budget — a handle that - // left the list and returned may converge now, so it earns fresh attempts. - viewportResubscribeBudgetRef.current.notifyListedHandles(liveHandles) - lastKnownTerminalCountRef.current = result.terminals.length - // Why: dedupe duplicate handles (rename/split race) to avoid a React duplicate-key throw; keep first for tab-strip order. - const seen = new Set() - const deduped = result.terminals.filter((t) => { - if (seen.has(t.handle)) { + return terminalInventoryRequest.run( + allowEmptyLoaded, + async (allowsEmpty, isCurrent) => { + try { + const response = await client.sendRequest('terminal.list', { + worktree: `id:${worktreeId}`, + includeVisualLayouts: false + }) + if (!isCurrent()) { return false } - seen.add(t.handle) + if (!response.ok) { + return false + } + const result = (response as RpcSuccess).result as { terminals: Terminal[] } + if (result.terminals.length === 0 && !allowsEmpty()) { + return true + } + // Why: require two consecutive empties before trusting 0, so transient empty responses don't flash the UI empty. + if (result.terminals.length === 0 && lastKnownTerminalCountRef.current > 0) { + lastKnownTerminalCountRef.current = 0 + return true + } + + const liveHandles = new Set(result.terminals.map((terminal) => terminal.handle)) + const pruneContext = { + liveHandles, + showNativeChat: showNativeChatRef.current, + activeHandle: activeHandleRef.current + } + // Why: terminal.list is the lifetime signal; lagging tab snapshots must not erase a user's buffered-mode opt-out. + // Sweep against the retained set, not the raw list: a chat-covered handle + // keeps its subscription across a graph reload, so erasing its live-input + // preference on the same refresh is the erasure this guard exists to stop. + pruneTerminalHandlesFromLiveInput(resolveRetainedTerminalHandles(pruneContext)) + defaultTerminalHandlesToLiveInput([...liveHandles]) + const shouldPrune = createTerminalPrunePredicate(pruneContext) + for (const handle of Array.from(terminalUnsubsRef.current.keys())) { + if (!shouldPrune(handle)) { + continue + } + unsubscribeTerminal(handle) + terminalRefs.current.delete(handle) + initializedHandlesRef.current.delete(handle) + viewportResubscribeBudgetRef.current.forget(handle) + clearTerminalLiveInputDefault(handle) + } + setTerminalKeyboardMetrics((prev) => pruneTerminalKeyboardMetrics(prev, shouldPrune)) + // Why: a chat-covered handle the host reports again refills its rearm budget, + // so an exhausted rearm can't lock the composer until leave-chat. + nativeChatStream.notifyListedHandles(liveHandles) + // Why: same absence-gated refill for the viewport-fit budget — a handle that + // left the list and returned may converge now, so it earns fresh attempts. + viewportResubscribeBudgetRef.current.notifyListedHandles(liveHandles) + lastKnownTerminalCountRef.current = result.terminals.length + // Why: dedupe duplicate handles (rename/split race) to avoid a React duplicate-key throw; keep first for tab-strip order. + const seen = new Set() + const deduped = result.terminals.filter((t) => { + if (seen.has(t.handle)) { + return false + } + seen.add(t.handle) + return true + }) + + const mergedTerminals = mergeTerminalListWithKnownRecords( + deduped, + terminalsRef.current, + sessionTabsRef.current + ) + setTerminals((prev) => + terminalRecordsEqual(prev, mergedTerminals) ? prev : mergedTerminals + ) + terminalsRef.current = mergedTerminals + + // Session tabs are the UI authority; terminal.list only refreshes per-handle metadata for existing terminal surfaces. return true - }) - - const mergedTerminals = mergeTerminalListWithKnownRecords( - deduped, - terminalsRef.current, - sessionTabsRef.current - ) - setTerminals((prev) => - terminalRecordsEqual(prev, mergedTerminals) ? prev : mergedTerminals - ) - terminalsRef.current = mergedTerminals - - // Session tabs are the UI authority; terminal.list only refreshes per-handle metadata for existing terminal surfaces. - } - } catch { - // Failed to list terminals - } finally { - fetchTerminalsInFlightRef.current = false - } + } catch { + // Failed to list terminals + return false + } + }, + opts.onPhysicalRequestStarted + ) }, [ client, @@ -1682,6 +1714,7 @@ export default function SessionScreen() { nativeChatStream, pruneTerminalHandlesFromLiveInput, subscribeToTerminal, + terminalInventoryRequest, unsubscribeTerminal ] ) @@ -2302,6 +2335,9 @@ export default function SessionScreen() { () => closedTabTombstonesRef.current.size > 0 || pendingBrowserFocusPageIdRef.current !== null || + // Why: tabs dropped a connected handle we still hold. `terminal.list` is the only + // remover, so keep the fast cadence until that sweep confirms or restores it. + hasConnectedTerminalAbsentFromSessionTabs(terminalsRef.current, sessionTabsRef.current) || // Why: a chat-covered handle that ran out of rearms and left `terminal.list` // was reminted by a desktop graph reload. Only a fresh tab snapshot carries // the replacement handle, so force one instead of holding the composer locked. @@ -2333,7 +2369,8 @@ export default function SessionScreen() { fetchSessionTabs, ensureSessionTabs, fetchPendingBrowserSessionTabs, - retryPendingTerminalRecovery + retryPendingTerminalRecovery, + requestTerminalInventoryRecovery } = useMobileSessionTabsReconciliation({ client, connState, @@ -2341,6 +2378,7 @@ export default function SessionScreen() { applySessionTabs, consumeAcceptedSessionTabs, fetchTerminals, + terminalInventoryRecoveryScopeKey: terminalInventoryRecoveryScope, hasRecoveryNeed: hasSessionTabsRecoveryNeed, pendingTerminalRecoveryContextKey, getPendingTerminalRecoveryContextKey, @@ -2349,6 +2387,11 @@ export default function SessionScreen() { ...sessionTabsFetchReporting }) + useEffect( + () => registerTerminalInventoryRecoveryAction(requestTerminalInventoryRecovery), + [registerTerminalInventoryRecoveryAction, requestTerminalInventoryRecovery] + ) + useEffect(() => { if (connState === 'connected') { return diff --git a/mobile/app/troubleshoot.tsx b/mobile/app/troubleshoot.tsx index c4313e88fcc..63fc0ddd477 100644 --- a/mobile/app/troubleshoot.tsx +++ b/mobile/app/troubleshoot.tsx @@ -1,13 +1,5 @@ import { useState, useCallback, useRef } from 'react' -import { - View, - Text, - StyleSheet, - Pressable, - ScrollView, - ActivityIndicator, - Platform -} from 'react-native' +import { View, Text, Pressable, ScrollView, ActivityIndicator, Platform } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { useRouter } from 'expo-router' import { @@ -20,7 +12,7 @@ import { XCircle, AlertTriangle } from 'lucide-react-native' -import { colors, spacing, typography } from '../src/theme/mobile-theme' +import { colors, spacing } from '../src/theme/mobile-theme' import { loadHosts } from '../src/transport/host-store' import { startDiagnosticFetchTimeout, @@ -32,6 +24,7 @@ import { unreachableHostDetail } from '../src/diagnostics/host-reachability' import { troubleshootCommonIssues } from '../src/diagnostics/troubleshoot-common-issues' +import { troubleshootScreenStyles as styles } from '../src/diagnostics/troubleshoot-screen-styles' type DiagnosticStatus = 'idle' | 'running' | 'done' @@ -281,135 +274,3 @@ export default function TroubleshootScreen() { ) } - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: colors.bgBase, - padding: spacing.lg - }, - topRow: { - flexDirection: 'row', - alignItems: 'center', - marginBottom: spacing.lg - }, - backButton: { - width: 36, - height: 36, - borderRadius: 18, - alignItems: 'center', - justifyContent: 'center', - marginRight: spacing.sm - }, - heading: { - fontSize: 20, - fontWeight: '700', - color: colors.textPrimary - }, - scroll: { - flex: 1 - }, - scrollContent: { - paddingBottom: spacing.xl - }, - diagnosticButton: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - gap: spacing.sm, - backgroundColor: colors.bgRaised, - borderRadius: 10, - paddingVertical: spacing.md, - paddingHorizontal: spacing.lg, - marginBottom: spacing.lg - }, - diagnosticButtonPressed: { - opacity: 0.7 - }, - diagnosticButtonDisabled: { - opacity: 0.5 - }, - diagnosticButtonLabel: { - fontSize: typography.bodySize, - fontWeight: '600', - color: colors.textPrimary - }, - checkRow: { - flexDirection: 'row', - alignItems: 'center', - gap: spacing.sm, - paddingVertical: spacing.sm + 2, - paddingHorizontal: spacing.md + 2 - }, - checkLabel: { - fontSize: typography.bodySize, - fontWeight: '500', - color: colors.textPrimary - }, - checkDetail: { - flex: 1, - textAlign: 'right', - fontSize: typography.metaSize, - color: colors.textMuted - }, - checkDetailFail: { - color: colors.statusRed - }, - sectionHeading: { - fontSize: typography.metaSize, - fontWeight: '600', - color: colors.textMuted, - textTransform: 'uppercase', - letterSpacing: 0.5, - marginBottom: spacing.sm, - marginTop: spacing.sm, - paddingHorizontal: spacing.xs - }, - section: { - backgroundColor: colors.bgPanel, - borderRadius: 12, - overflow: 'hidden', - marginBottom: spacing.lg - }, - separator: { - height: StyleSheet.hairlineWidth, - backgroundColor: colors.borderSubtle, - marginHorizontal: spacing.md - }, - rowPressed: { - backgroundColor: colors.bgRaised - }, - accordionHeader: { - flexDirection: 'row', - alignItems: 'center', - gap: spacing.sm + 2, - paddingVertical: spacing.md, - paddingHorizontal: spacing.md + 2 - }, - accordionTitle: { - flex: 1, - fontSize: typography.bodySize, - fontWeight: '500', - color: colors.textPrimary - }, - accordionBody: { - paddingHorizontal: spacing.md + 2, - paddingBottom: spacing.md, - gap: spacing.xs + 2 - }, - stepRow: { - flexDirection: 'row', - gap: spacing.sm - }, - bullet: { - fontSize: typography.metaSize, - color: colors.textMuted, - lineHeight: 18 - }, - stepText: { - flex: 1, - fontSize: typography.metaSize, - color: colors.textMuted, - lineHeight: 18 - } -}) diff --git a/mobile/package.json b/mobile/package.json index 75db0998903..9c3c4d4c0d0 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -25,43 +25,43 @@ "@xterm/addon-webgl": "0.20.0-beta.284", "@xterm/xterm": "6.1.0-beta.285", "buffer": "^6.0.3", - "expo": "^55.0.27", - "expo-build-properties": "^55.0.13", - "expo-camera": "^55.0.18", - "expo-clipboard": "^55.0.13", - "expo-constants": "^55.0.16", - "expo-crypto": "^55.0.14", - "expo-dev-client": "~55.0.35", - "expo-document-picker": "^55.0.13", - "expo-file-system": "55.0.19", - "expo-haptics": "^55.0.14", - "expo-image-manipulator": "^55.0.17", - "expo-image-picker": "^55.0.20", + "expo": "^55.0.30", + "expo-build-properties": "^55.0.18", + "expo-camera": "^55.0.23", + "expo-clipboard": "^55.0.17", + "expo-constants": "^55.0.17", + "expo-crypto": "^55.0.19", + "expo-dev-client": "~55.0.39", + "expo-document-picker": "^55.0.17", + "expo-file-system": "55.0.26", + "expo-haptics": "^55.0.18", + "expo-image-manipulator": "^55.0.21", + "expo-image-picker": "^55.0.24", "expo-keep-awake": "~55.0.8", - "expo-linking": "^55.0.15", + "expo-linking": "^55.0.17", "expo-modules-core": "~55.0.25", - "expo-network": "~55.0.14", - "expo-notifications": "^55.0.22", - "expo-router": "^55.0.14", - "expo-secure-store": "^55.0.13", - "expo-splash-screen": "^55.0.20", + "expo-network": "~55.0.18", + "expo-notifications": "^55.0.27", + "expo-router": "^55.0.18", + "expo-secure-store": "^55.0.18", + "expo-splash-screen": "^55.0.25", "expo-status-bar": "^55.0.6", "lowlight": "^3.3.0", "lucide-react-native": "^1.14.0", - "mermaid": "11.16.1", - "react": "^19.2.6", - "react-dom": "19.2.6", - "react-native": "^0.83.9", + "mermaid": "11.17.2", + "react": "^19.2.8", + "react-dom": "19.2.8", + "react-native": "^0.83.10", "react-native-gesture-handler": "^2.31.2", - "react-native-reanimated": "^4.3.0", + "react-native-reanimated": "4.3.4", "react-native-safe-area-context": "^5.7.0", "react-native-screens": "^4.24.0", "react-native-svg": "^15.15.4", "react-native-web": "^0.21.2", - "react-native-webview": "^13.16.1", + "react-native-webview": "13.16.2", "react-native-worklets": "^0.8.3", "tweetnacl": "^1.0.3", - "ws": "^8.21.0", + "ws": "^8.21.3", "zod": "~4.4.3", "zustand": "^5.0.13" }, @@ -73,21 +73,13 @@ "acorn": "8.15.0", "esbuild": "0.25.4", "expo-module-scripts": "^55.0.2", - "happy-dom": "^20.9.0", - "oxfmt": "^0.52.0", - "oxlint": "^1.71.0", - "react-test-renderer": "19.2.6", + "happy-dom": "^20.11.8", + "oxfmt": "^0.65.0", + "oxlint": "^1.80.0", + "react-test-renderer": "19.2.8", "tsx": "^4.22.4", "typescript": "6.0.3", "vite": "^8.0.16", - "vitest": "^4.1.9" - }, - "pnpm": { - "overrides": { - "xcode>uuid": "11.1.1" - }, - "patchedDependencies": { - "react-native@0.83.9": "patches/react-native@0.83.9.patch" - } + "vitest": "^4.1.11" } } diff --git a/mobile/patches/react-native-webview@13.16.2.patch b/mobile/patches/react-native-webview@13.16.2.patch new file mode 100644 index 00000000000..963f8884f38 --- /dev/null +++ b/mobile/patches/react-native-webview@13.16.2.patch @@ -0,0 +1,13 @@ +diff --git a/index.d.ts b/index.d.ts +index 10b9c145b920a6a2ba1fb09bd72150328fafe211..626a67a3d6aca587ee9e74a52b799a2c50b4c52b 100644 +--- a/index.d.ts ++++ b/index.d.ts +@@ -5,7 +5,7 @@ export { FileDownload, WebViewMessageEvent, WebViewNavigation } from './lib/WebV + + export type WebViewProps = IOSWebViewProps & AndroidWebViewProps & WindowsWebViewProps; + +-declare class WebView

extends Component { ++declare class WebView

extends Component { + /** + * Go back one page in the webview's history. + */ diff --git a/mobile/patches/react-native@0.83.9.patch b/mobile/patches/react-native@0.83.10.patch similarity index 100% rename from mobile/patches/react-native@0.83.9.patch rename to mobile/patches/react-native@0.83.10.patch diff --git a/mobile/pnpm-lock.yaml b/mobile/pnpm-lock.yaml index 01092f2acc9..72eb460a856 100644 --- a/mobile/pnpm-lock.yaml +++ b/mobile/pnpm-lock.yaml @@ -8,9 +8,12 @@ overrides: xcode>uuid: 11.1.1 patchedDependencies: - react-native@0.83.9: + react-native-webview@13.16.2: + hash: de6761dfa76a5491a23e49f1262566a8831cab26736a336fdffc5d4e7d05ff27 + path: patches/react-native-webview@13.16.2.patch + react-native@0.83.10: hash: 44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d - path: patches/react-native@0.83.9.patch + path: patches/react-native@0.83.10.patch importers: @@ -21,10 +24,10 @@ importers: version: 1.8.0 '@orca/expo-two-way-audio': specifier: file:./packages/expo-two-way-audio - version: file:packages/expo-two-way-audio(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: file:packages/expo-two-way-audio(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) '@react-native-async-storage/async-storage': specifier: ^2.2.0 - version: 2.2.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) + version: 2.2.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) '@xterm/addon-unicode11': specifier: 0.10.0-beta.285 version: 0.10.0-beta.285(@xterm/xterm@6.1.0-beta.285) @@ -38,129 +41,129 @@ importers: specifier: ^6.0.3 version: 6.0.3 expo: - specifier: ^55.0.27 - version: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + specifier: ^55.0.30 + version: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) expo-build-properties: - specifier: ^55.0.13 - version: 55.0.13(expo@55.0.27) - expo-camera: specifier: ^55.0.18 - version: 55.0.18(@types/emscripten@1.41.5)(expo@55.0.27)(react-native-web@0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 55.0.18(expo@55.0.30) + expo-camera: + specifier: ^55.0.23 + version: 55.0.23(@types/emscripten@1.41.5)(expo@55.0.30)(react-native-web@0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) expo-clipboard: - specifier: ^55.0.13 - version: 55.0.13(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-constants: - specifier: ^55.0.16 - version: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-crypto: - specifier: ^55.0.14 - version: 55.0.14(expo@55.0.27) - expo-dev-client: - specifier: ~55.0.35 - version: 55.0.35(expo@55.0.27) - expo-document-picker: - specifier: ^55.0.13 - version: 55.0.13(expo@55.0.27) - expo-file-system: - specifier: 55.0.19 - version: 55.0.19(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-haptics: - specifier: ^55.0.14 - version: 55.0.14(expo@55.0.27) - expo-image-manipulator: specifier: ^55.0.17 - version: 55.0.17(expo@55.0.27) + version: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-constants: + specifier: ^55.0.17 + version: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-crypto: + specifier: ^55.0.19 + version: 55.0.19(expo@55.0.30) + expo-dev-client: + specifier: ~55.0.39 + version: 55.0.39(expo@55.0.30) + expo-document-picker: + specifier: ^55.0.17 + version: 55.0.17(expo@55.0.30) + expo-file-system: + specifier: 55.0.26 + version: 55.0.26(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-haptics: + specifier: ^55.0.18 + version: 55.0.18(expo@55.0.30) + expo-image-manipulator: + specifier: ^55.0.21 + version: 55.0.21(expo@55.0.30) expo-image-picker: - specifier: ^55.0.20 - version: 55.0.20(expo@55.0.27) + specifier: ^55.0.24 + version: 55.0.24(expo@55.0.30) expo-keep-awake: specifier: ~55.0.8 - version: 55.0.8(expo@55.0.27)(react@19.2.6) + version: 55.0.8(expo@55.0.30)(react@19.2.8) expo-linking: - specifier: ^55.0.15 - version: 55.0.15(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: ^55.0.17 + version: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) expo-modules-core: specifier: ~55.0.25 - version: 55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) expo-network: - specifier: ~55.0.14 - version: 55.0.14(expo@55.0.27)(react@19.2.6) + specifier: ~55.0.18 + version: 55.0.18(expo@55.0.30)(react@19.2.8) expo-notifications: - specifier: ^55.0.22 - version: 55.0.22(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + specifier: ^55.0.27 + version: 55.0.27(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3) expo-router: - specifier: ^55.0.14 - version: 55.0.14(50649306d987d6f4e510b7a8e94ea6ba) + specifier: ^55.0.18 + version: 55.0.18(2f99795f9796def5cdb1516a493dc117) expo-secure-store: - specifier: ^55.0.13 - version: 55.0.13(expo@55.0.27) + specifier: ^55.0.18 + version: 55.0.18(expo@55.0.30) expo-splash-screen: - specifier: ^55.0.20 - version: 55.0.20(expo@55.0.27)(typescript@6.0.3) + specifier: ^55.0.25 + version: 55.0.25(expo@55.0.30)(typescript@6.0.3) expo-status-bar: specifier: ^55.0.6 - version: 55.0.6(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 55.0.6(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) lowlight: specifier: ^3.3.0 version: 3.3.0 lucide-react-native: specifier: ^1.14.0 - version: 1.14.0(react-native-svg@15.15.4(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 1.14.0(react-native-svg@15.15.4(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) mermaid: - specifier: 11.16.1 - version: 11.16.1 + specifier: 11.17.2 + version: 11.17.2 react: - specifier: ^19.2.6 - version: 19.2.6 + specifier: ^19.2.8 + version: 19.2.8 react-dom: - specifier: 19.2.6 - version: 19.2.6(react@19.2.6) + specifier: 19.2.8 + version: 19.2.8(react@19.2.8) react-native: - specifier: ^0.83.9 - version: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + specifier: ^0.83.10 + version: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) react-native-gesture-handler: specifier: ^2.31.2 - version: 2.31.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 2.31.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-reanimated: - specifier: ^4.3.0 - version: 4.3.0(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: 4.3.4 + version: 4.3.4(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-safe-area-context: specifier: ^5.7.0 - version: 5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-screens: specifier: ^4.24.0 - version: 4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-svg: specifier: ^15.15.4 - version: 15.15.4(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 15.15.4(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-web: specifier: ^0.21.2 - version: 0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react-native-webview: - specifier: ^13.16.1 - version: 13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: 13.16.2 + version: 13.16.2(patch_hash=de6761dfa76a5491a23e49f1262566a8831cab26736a336fdffc5d4e7d05ff27)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) react-native-worklets: specifier: ^0.8.3 - version: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) tweetnacl: specifier: ^1.0.3 version: 1.0.3 ws: - specifier: ^8.21.0 - version: 8.21.0 + specifier: ^8.21.3 + version: 8.21.3 zod: specifier: ~4.4.3 version: 4.4.3 zustand: specifier: ^5.0.13 - version: 5.0.13(@types/react@19.2.14)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) + version: 5.0.13(@types/react@19.2.14)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8)) devDependencies: '@types/react': specifier: ^19.2.14 version: 19.2.14 '@types/react-native': specifier: ^0.73.0 - version: 0.73.0(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + version: 0.73.0(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) '@types/react-test-renderer': specifier: 19.1.0 version: 19.1.0 @@ -175,19 +178,19 @@ importers: version: 0.25.4 expo-module-scripts: specifier: ^55.0.2 - version: 55.0.2(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.25.4)(eslint@9.39.4)(expo@55.0.27)(jest@29.7.0(@types/node@26.1.2))(prettier@2.8.8)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react-refresh@0.14.2)(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + version: 55.0.2(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.25.4)(eslint@9.39.4)(expo@55.0.30)(jest@29.7.0(@types/node@26.1.2))(prettier@2.8.8)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react-refresh@0.14.2)(react-test-renderer@19.2.8(react@19.2.8))(react@19.2.8) happy-dom: - specifier: ^20.9.0 - version: 20.11.1 + specifier: ^20.11.8 + version: 20.11.8 oxfmt: - specifier: ^0.52.0 - version: 0.52.0 + specifier: ^0.65.0 + version: 0.65.0 oxlint: - specifier: ^1.71.0 - version: 1.71.0 + specifier: ^1.80.0 + version: 1.80.0 react-test-renderer: - specifier: 19.2.6 - version: 19.2.6(react@19.2.6) + specifier: 19.2.8 + version: 19.2.8(react@19.2.8) tsx: specifier: ^4.22.4 version: 4.22.4 @@ -198,8 +201,8 @@ importers: specifier: ^8.0.16 version: 8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0) vitest: - specifier: ^4.1.9 - version: 4.1.9(@types/node@26.1.2)(happy-dom@20.11.1)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)) + specifier: ^4.1.11 + version: 4.1.11(@types/node@26.1.2)(happy-dom@20.11.8)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)) packages: @@ -1578,8 +1581,8 @@ packages: '@expo-google-fonts/material-symbols@0.4.34': resolution: {integrity: sha512-PdwETUhvu1gHF1e8eIyEHnBJLq/dRNoTrT5yhsGUfGyRxH5pbm54dF3+QPknxwMKj0M1trN7PSelYz+yzlt3lA==} - '@expo/cli@55.0.33': - resolution: {integrity: sha512-mCpv91YrgiQUCXEHbNOQNPeStO4NKvYaXgKuzzLjklrCUPf3f+u0oYcS5rl3KoFvTEifhOiuA0VkLDR8U0GGPg==} + '@expo/cli@55.0.36': + resolution: {integrity: sha512-jVMEXmxeUKXAzJdRWQer7fyogjPMYiTbrGOrlioJlwMuFqKfao3FeFInmATMNGLhNN01aBs/s6pnJKqiAdlUQg==} hasBin: true peerDependencies: expo: '*' @@ -1594,8 +1597,8 @@ packages: '@expo/code-signing-certificates@0.0.6': resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==} - '@expo/config-plugins@55.0.10': - resolution: {integrity: sha512-1txnRnMLIO5lM/Of/VyvDkCwZap0YFvCyfSTIlUQamhwhx6Rh7r8TXfcIstaDYUQ7X6GTMkNxLXWbcYS6ZAFDw==} + '@expo/config-plugins@55.0.11': + resolution: {integrity: sha512-85ZSmIK8rMfvYbG/2IHtwnykVdb6LI0ZavduM3ZwUMThyyVegYjVsO5Zek2ec8xzPhCmYX0ar5onnFEcwUDUlw==} '@expo/config-plugins@55.0.8': resolution: {integrity: sha512-8WfWTRntTCcowfOS+tHdB0z98gKetTwktg4G5TWkCkXVa8Jt1NUnvzaaU4UHk2vbR2U4N84RyZJFizSwfF6C9g==} @@ -1603,11 +1606,14 @@ packages: '@expo/config-types@55.0.5': resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} + '@expo/config-types@55.0.6': + resolution: {integrity: sha512-S+GJKYoIjnWlert/9vXuTohaTsMbyOLSVxdIgPgoq3P4N1p4CWrfyZLnz6qRug8wYSO5fcYcS9mFleyEP8wRLg==} + '@expo/config@55.0.16': resolution: {integrity: sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==} - '@expo/config@55.0.18': - resolution: {integrity: sha512-yezuyUk1VvVuwVyvKQrMHGosoC0WTh7HFAycpISMyeinSUHDjEBGvHUSQxtQ/71MR4g9lPJkEhFKeRjGx7I/Yg==} + '@expo/config@55.0.21': + resolution: {integrity: sha512-yHmSSnBrm2ecB1DNsCrZZrScVnvXrtg3+PAMwI3ocxEtD9YK8yX5xV2xi2pmor9TYitAO+udFWxo+XDEGibznw==} '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} @@ -1630,16 +1636,20 @@ packages: react: '*' react-native: '*' - '@expo/env@2.1.2': - resolution: {integrity: sha512-RJtGFfj/ygO/6zcVbV3cckHf4THcEkv5IZft1GjCB3dfT6axvzvIwXE9EiQqQYmGHcQ+ZrvC8xZcIhiHba0pYg==} + '@expo/env@2.1.3': + resolution: {integrity: sha512-Rhu/lJ1kOhqzJvLwW0iB4WKUzB1nFa8WBwXFL44qkSTNwibjrbI8lA46Ix6W2MMTdlUqL1m85Gdyx0T7nGpREg==} engines: {node: '>=20.12.0'} - '@expo/fingerprint@0.16.7': - resolution: {integrity: sha512-BH8sicYOqZ1iBMwCVEGIz6uTTfylosjc49FoMmCYIzKOiYdiVehsfoYBwyfxwWIiya1VMhm1gv0cgOP8fxHpDw==} + '@expo/env@2.4.2': + resolution: {integrity: sha512-28pqaEqwnmLduZ00Pq9HkSzE5wbj1MTwp5/n8nm8rD8MCjR9eUnVOwmNksPI3Be2ReAPO/DbPn1puy0mvoocsQ==} + engines: {node: '>=20.12.0'} + + '@expo/fingerprint@0.16.8': + resolution: {integrity: sha512-RaLOikl+alkvG9ZrBQFGi3kVXJdG5GQXY1H3V1ZFCwFyhFikwuBozVrl4KL7U+N0Tm8Bf1qDmpTEIx8JOyrQog==} hasBin: true - '@expo/image-utils@0.8.14': - resolution: {integrity: sha512-5Sn+jG4Cw+shC2wDMXoqSAJnvERbiwzHn05FpWtD5IBflfTIs5gUmjzwiGVyjOdlMSQhgRrw/AymPbmO9h9mpQ==} + '@expo/image-utils@0.8.17': + resolution: {integrity: sha512-1eVrX6FFkPNl9DJNiw3Gjsf6PtG7HttbapEVvcROVrA9PCMikujOJWWHDYKGptmKoVIIVajFZE8UHGHUb3mPug==} '@expo/json-file@10.0.14': resolution: {integrity: sha512-yWwBFywFv+SxkJp/pIzzA416JVYflNUh7pqQzgaA6nXDqRyK7KfrqVzk8PdUfDnqbBcaZZxpzNssfQZzp5KHrA==} @@ -1653,8 +1663,8 @@ packages: '@expo/json-file@11.0.0': resolution: {integrity: sha512-pHJCETqFL5x5BzNV6cEPwjwuECgGmnl0bNmfHIJ6LM1tlh2eVXi5HEdit3zby/JO/B8Otk5cgcqtJXgvvUat3A==} - '@expo/local-build-cache-provider@55.0.14': - resolution: {integrity: sha512-Itv/Wm8wBuq2QoJeda7N0Ys2ciq3ZQW+JLL8XijWMYOO/llieKeZue95FsuaREp3Ijdo0pSw0/cu+EkrwmU0vA==} + '@expo/local-build-cache-provider@55.0.16': + resolution: {integrity: sha512-/m2kb/+G2ryZ60FPZcuiLXzXp55p/X8QPXuU5CV/il0sSJcY0sQFICfM9ApokzHtzNQ0nDQOBUoQY3weilgP2g==} '@expo/log-box@55.0.11': resolution: {integrity: sha512-JQHFLWkskIbJi6cxYMjErx8lQqfFJilDQLKmdTO3m3YkdmN9GE/CrzjOfVlCG0DGEGZJ90br0pGKvGPdXNsHKw==} @@ -1664,16 +1674,16 @@ packages: react: '*' react-native: '*' - '@expo/log-box@55.0.12': - resolution: {integrity: sha512-f9ARS8J60cq3LLNdIqmUjYwyerBzVS5Ecp7KjIf3GOIPjW0571rkcwLz4/U18l/1DeSkSzIkYsNl2TC9oTdWaQ==} + '@expo/log-box@55.0.13': + resolution: {integrity: sha512-pV623uwyKjw/L1HVWOpwWOu/ISLH1+c+ESVv30alQMbEaE3cLcwcQ+UnHiAGayMBNMQwK57eckOgH40RBXHfCA==} peerDependencies: '@expo/dom-webview': ^55.0.6 expo: '*' react: '*' react-native: '*' - '@expo/metro-config@55.0.24': - resolution: {integrity: sha512-GQ8vernAY3BClpntFj+DDm4rmTpuFZYKxZ/82Q0XTZAOHnum68WIgRbgG2aRpAyVVs1wRBToKlLiSFCkpSS41w==} + '@expo/metro-config@55.0.27': + resolution: {integrity: sha512-oikn1NPFpQgNqL/HTqA6oAG2Af/BwldIezlecTidc8D+fkFgLFKkZHUq1Hh1g/vuCPGTQNWDlHla13dAgYwRvg==} peerDependencies: expo: '*' peerDependenciesMeta: @@ -1691,8 +1701,8 @@ packages: react-dom: optional: true - '@expo/metro@55.1.1': - resolution: {integrity: sha512-/wfXo5hTuAVpVLG/4hzlmD9NBGJkzkmBEMm/4VICajYRbj7y8OmqqPWbbymzHiBiHB6tI9BnsyXpQM6zVZEECg==} + '@expo/metro@55.1.2': + resolution: {integrity: sha512-EOBoqqX4jD7JvHBHKDoek8SmWyAFPuJePyDSqIAhIjOCPAM67fVxd4+pCXJ6SDK1P9so55v2iTFBwCoeCmEj4Q==} '@expo/npm-proofread@1.0.1': resolution: {integrity: sha512-yDyBlNIgg+rKoKCOVM9ZyAtgqRx6gHw+JtmZTrYYW4auAfwS6kE/iInmCpVXPqRy0OhJHgXj6q5PCgWELLVMeg==} @@ -1711,13 +1721,8 @@ packages: '@expo/plist@0.5.4': resolution: {integrity: sha512-Jqppj0FULNq6Zp5JtQrFICl8TtpMjwwUbxEcEC2T3z7m+TOrTQEHZXz3D3Ay7vhbmvD+VMgfWJ4ARclJXeN8Eg==} - '@expo/prebuild-config@55.0.17': - resolution: {integrity: sha512-Mcs+dg4Ripu0yCtzf66KZr18PehI1O8HxzJw+G5SUF8VWX+ic99aci1PltvmydWepLwTQL6ykmpXicAUA31IqA==} - peerDependencies: - expo: '*' - - '@expo/prebuild-config@55.0.19': - resolution: {integrity: sha512-rLGjUXW0EUoxu/PJUOC0Lz5PEs27DmBA9Es3t2xV2ftI3kGZJK6oNt1vVq5D/Rn6MhZ5SFxqd3kziyP8ELoN6g==} + '@expo/prebuild-config@55.0.22': + resolution: {integrity: sha512-2p1lE2hOCy9HUV9qxbEqmetxUgcBnVY8jR+j/SYRXgaBeHalyQ5d09Ol5XL36/HO2fViK8VmSnTbS7C3t8eFGg==} peerDependencies: expo: '*' @@ -1729,15 +1734,23 @@ packages: typescript: optional: true - '@expo/router-server@55.0.18': - resolution: {integrity: sha512-W0VsvIiR48OvdlAOUlag4qspGYT/DV4srfYowlbYxwZh5Qw0MjiZAID4Zt7F0qynGZZxx8OZPpFhIX7XsqtRmg==} + '@expo/require-utils@55.0.8': + resolution: {integrity: sha512-DDS5R67iz2SJwncbpcUMHtnsq31dSfllhaEncKxGlK0/ewgc2CaXUCkDA2AumfT7ubnSXiPkU9Gn8v2xCrvj+A==} peerDependencies: - '@expo/metro-runtime': ^55.0.11 + typescript: ^5.0.0 || ^5.0.0-0 + peerDependenciesMeta: + typescript: + optional: true + + '@expo/router-server@55.0.19': + resolution: {integrity: sha512-bm2CFp9eI9biqZXz7Vkske0LXHZaLyonWV6sTEWUaR8zJ0NdVnUxb1Vd0iCdhW8GtweOUfMK4z7gojd0kydxjA==} + peerDependencies: + '@expo/metro-runtime': ^55.0.12 expo: '*' - expo-constants: ^55.0.16 + expo-constants: ^55.0.17 expo-font: ^55.0.8 expo-router: '*' - expo-server: ^55.0.11 + expo-server: ^55.0.12 react: '*' react-dom: '*' react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 @@ -1751,8 +1764,8 @@ packages: react-server-dom-webpack: optional: true - '@expo/schema-utils@55.0.4': - resolution: {integrity: sha512-65IdeeE8dAZR3n3J5Eq7LYiQ8BFGeEYCWPBCzycvafL7PkskbCyIclTQarRwf/HXFoRvezKCjaLwy/8v9Prk6g==} + '@expo/schema-utils@55.0.5': + resolution: {integrity: sha512-wdV4SzWJ/l+6y/r9vDaqPqXGyfxUD1igbX8rRbRBfkVXenAUY2qenq6HF4S0iJ0pjpVDNTANn5aQY7VV55hhsA==} '@expo/sdk-runtime-versions@1.0.0': resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} @@ -1921,8 +1934,8 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@mermaid-js/parser@1.2.0': - resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@mermaid-js/parser@1.2.1': + resolution: {integrity: sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw==} '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} @@ -1947,246 +1960,246 @@ packages: '@oxc-project/types@0.137.0': resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==} - '@oxfmt/binding-android-arm-eabi@0.52.0': - resolution: {integrity: sha512-17EMSJnQ9g+upVHrAUYDMfH5lvRKQ9Nvg8WtEoH72oDr1VpWz+7/o3tD97U1EToen2YAQ/68JmtDYkQUi20dfQ==} + '@oxfmt/binding-android-arm-eabi@0.65.0': + resolution: {integrity: sha512-M10Gs1SSpTNI6ahGx3M/OlIdUF4hkaP6OgUb+MS79t/Pgflk3r1nW5gPFqsZGUAXg0H1AfANT9AvLdBSTIhZKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.52.0': - resolution: {integrity: sha512-A2G1IdwGEW2lLJkIxcvuirRH1CzSl/e0NX11zTlW1gvxJThfwbI/BEoaKrTNpm7M2FchvIf6guvIQU7d5iz+OQ==} + '@oxfmt/binding-android-arm64@0.65.0': + resolution: {integrity: sha512-6DXH5sftNlaHpWJG50hFMF+Qxtq5D2TmahvcDPxWNcGIf8qrC9Y0YgHYcYZ2hlWzaccKXh/f3GcssH8vtkl4JA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.52.0': - resolution: {integrity: sha512-f9+bLvOYxy7NttCLFTvQ7afmqDOWY4wIP9xdvfj5trQ1qj6f2UFAGwZESlfsMjvJNTyRpXfIlOanCI9FOvoeQA==} + '@oxfmt/binding-darwin-arm64@0.65.0': + resolution: {integrity: sha512-K9m7lr53pcOLETNsC88sWes/GWHUGjZyHx95UhYcSXy0r30haLdeXlSufSenEAtoLaW753WN8/l4M7GYcRt6cg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.52.0': - resolution: {integrity: sha512-YSTB9sJ5nnQd/Q0ddHkgof0ZCHPAnWZT1IW2SJ8omz7CP7KluJhO1fNHrpqdxCtpztJwSs4hY1uAee35wKxxaw==} + '@oxfmt/binding-darwin-x64@0.65.0': + resolution: {integrity: sha512-sTNwIx1gre3MyiHOPLu7IGW4UyMScYL4DTmJT01p4vzB0En+OJUQz6KuH8t0PpsClRSaMuY3b0QmtoPItfO8Lg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.52.0': - resolution: {integrity: sha512-NIrRNTTPCs4UbmVs0bxLSCDlLCtIRMJIXklNKaXa5Oj2/K1UIMBvgE8+uPVo01Io3N9HF0+GAX+aAHjUgZS7vA==} + '@oxfmt/binding-freebsd-x64@0.65.0': + resolution: {integrity: sha512-lYZMVIiIpnjGu5hJb2jxA8NYQ/e0OTGuaiAf4dqlGPNnPmUTu23FZRMltmjro/KkQm1uE4NT4n5yJ2zWmKcpfA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.52.0': - resolution: {integrity: sha512-JXUCde8mn3GpgQouz2PXUokgy/uT1QrRJBL2s983VWcSQp62wTFYiNXgTKdeo1Jgbr0IgUnKKvzIk/YBlj/nVQ==} + '@oxfmt/binding-linux-arm-gnueabihf@0.65.0': + resolution: {integrity: sha512-gIdXFAt/bURnjxuoedDEWdZ0PEWEmdDcm8qdpoFYYvW3QMk/5D4vUaH4mlMeRpeTdST4izUgHVO6RawQ4QulJw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.52.0': - resolution: {integrity: sha512-psbUXaRZ+V8DaXz10Qf7LSHtdtdKAmC8fxXgeU608jjzrmWK4quamZMOpl6sf+dikoFHA85uE93Q0BqxrCdQrQ==} + '@oxfmt/binding-linux-arm-musleabihf@0.65.0': + resolution: {integrity: sha512-jJVyADto7gA2AaX5qAjAexrxx9PJQaKWOe8PICE7yKMbjBRyOHcmj9TtVJ+MZYDUQ3hodU0AcoTj0jFQ1W4C6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.52.0': - resolution: {integrity: sha512-Jw7MgWUU9lcLCcy82updISP3EthTlfvAwR6gWNxPzqly7+fLvOi2gHQE9xXQjpqaVLm/8P+gOzlv9ODuoVlaaw==} + '@oxfmt/binding-linux-arm64-gnu@0.65.0': + resolution: {integrity: sha512-p3RFkB+u7u+8up99b/NEcI1hdpLDiGgJYNwDorB60n7eH+eKposAKuMBxx+NqB3b+sJP4CZmYDh9G7X62tUsKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.52.0': - resolution: {integrity: sha512-wZg6bLjDvh2KibyI3QFUYo8GTXneIFsd0JvehtvJiUmQ8WRPERgxd/VM4ctWb86U5FT1FkqgS8/wZKVB+AZScg==} + '@oxfmt/binding-linux-arm64-musl@0.65.0': + resolution: {integrity: sha512-5Prb0uFzJHr+OUD/qS/TmU526wD+PaHDsm3KoRiUXbMIDpTSErjeQYkK3OQeshAvD/PuLa9WGEi9WPajjdOZJg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.52.0': - resolution: {integrity: sha512-IngE8uxhNvxcMrLjZNDo9xNLY7rEK33AKnaMd2B46he1e/mz2CfcW6If/U1wUjdRZddm1QzQaciqZkuMkdh1FA==} + '@oxfmt/binding-linux-ppc64-gnu@0.65.0': + resolution: {integrity: sha512-S8svxTp81obnF3admN9yd+u2rOYXtyzThLGBTg1PY6TPtGcC09BaaXLQD+TBSMa7yvqhCDZ8DFri+S/yG60qCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.52.0': - resolution: {integrity: sha512-H3+DdFMv/efN3Efmhsv18jDrpiWWqKG7wsfAlQBqAt6z/E2Bx+TwEj2Nowe51CPOWB8/mFBC2dAMSgVFLvvowA==} + '@oxfmt/binding-linux-riscv64-gnu@0.65.0': + resolution: {integrity: sha512-WtXBr75G/h2qOHy8SiGtC1R6aS3jt4mE52v1D8AtwMXIgoOmSNP9lKvbSaTRoL0e5wsMPoi6T72QWDYPu+S+nA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.52.0': - resolution: {integrity: sha512-zji+1kb7lJKohSDjzC1IsS+K/cKRs1hdVf0ZH0VbdbiakmtLvN9twBoXo/k8VdjFax7kfo+DyPxS7vv52br1aw==} + '@oxfmt/binding-linux-riscv64-musl@0.65.0': + resolution: {integrity: sha512-YwSLVvpaz4o/nv/miiPEBJz+eJ+VmbgNIrao6RccK9ce+L5EA8wP+ZD0uFeq6wKOza6zoWv/dR0sj6lip6R3EA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.52.0': - resolution: {integrity: sha512-hcLBYedpCy7ToUvvBidWk7+11Yhg1oAZ4+6hKPic/mQI6NaqXJSXMps5nFlwUuX2ewhtLZZDPg63TI042qGKBg==} + '@oxfmt/binding-linux-s390x-gnu@0.65.0': + resolution: {integrity: sha512-XQTPqgvyrgkKcFq+Tp2eK6JS7sqqJ+nRmy2Fav4j3I+i4dJoPJm7YwEdoeSDX9xkqj9jZ/lWfF3bXUWztIrn6A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.52.0': - resolution: {integrity: sha512-IDO2loXK2OtTOhSPchU9MW25mWL2QCDGdJbjN8MXKZVS80qXe5gMTwQWu/gMJ3juoBHbkuUZNB2N1LHzNT7DoA==} + '@oxfmt/binding-linux-x64-gnu@0.65.0': + resolution: {integrity: sha512-cjZlx6S/VkeCNWCbwZriTnLnZeTcV3DEyeRGSw/2wwLP9viq+C0bJ4bC1k/ZLkFxDcB1lUgSasPkYGP1bdraOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.52.0': - resolution: {integrity: sha512-mAV2Hjn0SatJ+KoAzKUC3eJhdJ8wv+3m1KyuS0dTsbF0c5weq+QrCt/DRZZM+uj/XiKzCDEUKYsBF30e2qkcyw==} + '@oxfmt/binding-linux-x64-musl@0.65.0': + resolution: {integrity: sha512-2azCjxdLtK4zCcIOU1dlXlU0xxfbPi6EjwWx7Ac7teWPidIIDOcIhudup83xNCKYhtqeVd/gaVDOxbUq4syXWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.52.0': - resolution: {integrity: sha512-vd4npaUIwChxp7XzkqmepBWTT9YMcSe/NBApVGPC30/lLyOVaV3dvma1SKo03t8O73BPRAG7EyJzGlN5cJM5hQ==} + '@oxfmt/binding-openharmony-arm64@0.65.0': + resolution: {integrity: sha512-KXQ7xi1e/voP0IQaw6fG6XY4Z5+Llf1XmRSZS1t7pVFCecFJ0iXaboKmVwjFtp5MLlT5iWQrJ2U1C3GJdZ2u+Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.52.0': - resolution: {integrity: sha512-k2sz6gWQdMfh5HPpIS+Bw/0UEV/kaK2xuqJRrWL233sEHx9WLlsmvlPFM4HUNThkYbSN0U0vPW7LVKZWDS8hPQ==} + '@oxfmt/binding-win32-arm64-msvc@0.65.0': + resolution: {integrity: sha512-2FbbjG5jEqLSLKVJwBap84uJfpn5Y5A53KEO0aUNr+zeiRB9nyPUIFMcSbZVMFLitfBytFWRNngozXYjb6Rsbw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.52.0': - resolution: {integrity: sha512-rhke69GTcArodLHpjMTfNnvjTEBryDeZcUCKK/VjXDMtfTULl6QRh0ymX5/hbCUv2WjYm9h/QbW++q2vE15gWQ==} + '@oxfmt/binding-win32-ia32-msvc@0.65.0': + resolution: {integrity: sha512-LJ+ZacAPSjegDOnSLyA1TMWAhdDrsK4el3REdr1oL2UtVBCMhO2II/Sb3cEW6mF2MfLhl8hDNCSvc7KSbgk3LQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.52.0': - resolution: {integrity: sha512-q5xL7oeXkZdEtNZWBdvehJcmt+GRu9l2bK40yJs1jJXlqq+r0Hygb1rTjq+FM2o/2xyt4cufH6KRplHp3Jjsvw==} + '@oxfmt/binding-win32-x64-msvc@0.65.0': + resolution: {integrity: sha512-higu9cWEO6XXFzATD1jf0mCK34rNfN2H9JrJie7QB1IhleVpTh0QlLH9Ip2C1H/Nd5n0v5pvRtC+5R0uE4HpVg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.71.0': - resolution: {integrity: sha512-ImGmd1njEg4FEJH03jhRnveEegtO3czCtfptvaHivKAZQIYATbVFBrrzbaYMYv0oJioTnxZAZVSyV+oL7W8S2g==} + '@oxlint/binding-android-arm-eabi@1.80.0': + resolution: {integrity: sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.71.0': - resolution: {integrity: sha512-4A5BEexBrwY1YFF8Kiq/lp/wQPRG79G3BWIE1FuWaM5MvmpYSd+7ZySVcKkHdwo0UDzdQGddp6pD9mpctMqLnw==} + '@oxlint/binding-android-arm64@1.80.0': + resolution: {integrity: sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.71.0': - resolution: {integrity: sha512-9wJA9GJulLwS2usU3CEisI/ESDO1n1z9eyTCvApMDrAkbJ1ve0mORgTMjcWWsKxkzkeZ2N/Gpra5IQE7x8tYgQ==} + '@oxlint/binding-darwin-arm64@1.80.0': + resolution: {integrity: sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.71.0': - resolution: {integrity: sha512-PlLCjS06V0PeJMAJwzjrExw1sYNW9Gch3JtNlcwwZDXGlTYDuwHNN89zYH8LTXFfgkVtsYvs2nv0FqrzyuFDzg==} + '@oxlint/binding-darwin-x64@1.80.0': + resolution: {integrity: sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.71.0': - resolution: {integrity: sha512-Lhil7bWre0ncxbUoDoxfS0JzpTz17BRQKW7iwoAUY8GJ66+WwJEfYPCFJ1P0WgVZR5/O/b3Q2pENlHOjeXLOGQ==} + '@oxlint/binding-freebsd-x64@1.80.0': + resolution: {integrity: sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.71.0': - resolution: {integrity: sha512-Oo9/L58PYD3RC0x05d2upAPLllHytTjHQGsnC06P6Ynn7jKkp5mdImQxXdJ3+FnBaKspNpGogzgVsi6g872LiA==} + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': + resolution: {integrity: sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.71.0': - resolution: {integrity: sha512-mSHfyfgJrEbyIR29ejaeS50BdPk+GoNPlC1dckpDiUZbJAIel68sjSMdOt4WY0/gva+ECC7FNITQkxMJU+vSBw==} + '@oxlint/binding-linux-arm-musleabihf@1.80.0': + resolution: {integrity: sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.71.0': - resolution: {integrity: sha512-n9yY4M2tiy3aij4AqtlnspzpfdpeT5JQfK2/w2d8oyp5W0FRwOb1dIeX99nORNcxGr08iD9bH8N5XFz3I2iy8w==} + '@oxlint/binding-linux-arm64-gnu@1.80.0': + resolution: {integrity: sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.71.0': - resolution: {integrity: sha512-fJZrs5sDZtTaPIOiemRQQmo82Ezy+vOGXemPc4Ok7iVVsYsFa7SlW6Z5XN819VfsqBHRm3NJ3rTdnR8+bJYJdQ==} + '@oxlint/binding-linux-arm64-musl@1.80.0': + resolution: {integrity: sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.71.0': - resolution: {integrity: sha512-cwl7VKGERIy9p+G+AvZdfy/06q0aHXaTt/mMRReC751iuNYJgqKjB7NydXSS30nBT9vtr2tunciOtrR4fD6FUA==} + '@oxlint/binding-linux-ppc64-gnu@1.80.0': + resolution: {integrity: sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.71.0': - resolution: {integrity: sha512-eZ8ieVXvzGi8jr7+ybQGPK2STw3mldfxZlgA2738iflfB/rzA69sE6m5rDRpQaxC7dpm745Enlh1Tod0QAk9Gg==} + '@oxlint/binding-linux-riscv64-gnu@1.80.0': + resolution: {integrity: sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.71.0': - resolution: {integrity: sha512-puMDbQYe6+NXwfMusojoA7CXGn2b3utukmd23PQqc1E3XhVCwyZ+FueSMzDYeNgDV2dUfIVXAAKZBcFDeCL6sA==} + '@oxlint/binding-linux-riscv64-musl@1.80.0': + resolution: {integrity: sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.71.0': - resolution: {integrity: sha512-4NJLxBs1ujISCt3L/1FcywLs73PWtJuw+piD6feK2V6h6OS6P7xu9/sWt1DTRLibe6QCzmfZzmM/2HPORoV/Lg==} + '@oxlint/binding-linux-s390x-gnu@1.80.0': + resolution: {integrity: sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.71.0': - resolution: {integrity: sha512-cFDaiR8L3430qp88tfZnvFlt3KotFhR/DlbIL0nHOMMYiG/9Wy4l+6f7t8G8pTa9bd8Lt8+M0y/qjRQ/xcB74g==} + '@oxlint/binding-linux-x64-gnu@1.80.0': + resolution: {integrity: sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.71.0': - resolution: {integrity: sha512-orfixdt76KlpNly9z0PkWBBNfwjKz+JFVLP/7wnVchlKNU9Dpt9InU/ZggeSej6fC7qwHmHNOGlhLnQXcYoGuA==} + '@oxlint/binding-linux-x64-musl@1.80.0': + resolution: {integrity: sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.71.0': - resolution: {integrity: sha512-9emQu2lAp6yhPB3XuI+++vR+l/o6JR1X+EpxwcumPdQXBWXEPAsquPGL7l158EqU8SebQMXTUa/S5zN98juyHw==} + '@oxlint/binding-openharmony-arm64@1.80.0': + resolution: {integrity: sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.71.0': - resolution: {integrity: sha512-bd5kI8spYwTm3BILDtGhi73zoup5dw8MlPQNT8YB3BD5UIsjNe3K9/4ctrzQMX4SZMoK5HgzVLkLJzacEXB7fA==} + '@oxlint/binding-win32-arm64-msvc@1.80.0': + resolution: {integrity: sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.71.0': - resolution: {integrity: sha512-W4HvOHGzVLHcrmFu+bMrJlho+/yrlX5ZNdJZqGe8MEldkQG+RHYhxxad9P4jvWAYFmIqUA5i9DQ8QsJqSU9GIw==} + '@oxlint/binding-win32-ia32-msvc@1.80.0': + resolution: {integrity: sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.71.0': - resolution: {integrity: sha512-D2kyEIPHk/G/wiZLnwTVC/sVst+T/lKldVOjAFpgTIBUAOlry72e5OiapDbDBF4LfJLkN5ypJb/8Eu6yJzkveQ==} + '@oxlint/binding-win32-x64-msvc@1.80.0': + resolution: {integrity: sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2428,8 +2441,12 @@ packages: peerDependencies: react-native: ^0.0.0-0 || >=0.65 <1.0 - '@react-native/assets-registry@0.83.9': - resolution: {integrity: sha512-9MrShFZWvHybyjN8nj/rKW53hLpPOXMdEF8FOdDXRNu8oQ396BLknCMFeSCFhAHiCDVqQfah5iIV8S1wqXnxFA==} + '@react-native/assets-registry@0.83.10': + resolution: {integrity: sha512-AcVfyQ+8HsWCecXEnSaRffP71KqaWrhNB8bLulYCpKO7i5h/lmwgF191uafU/WiS0LbEMTGlXwWBshPto1phyA==} + engines: {node: '>= 20.19.4'} + + '@react-native/babel-plugin-codegen@0.83.10': + resolution: {integrity: sha512-iRfhxsOePloy12TUzpL9dCwnxLi3eurg8+JurSozAmWh4HtmKu0IJHNjbEKk9htI5n4RlFom8LQ9vVcvgWOTbw==} engines: {node: '>= 20.19.4'} '@react-native/babel-plugin-codegen@0.83.6': @@ -2440,6 +2457,12 @@ packages: resolution: {integrity: sha512-5Dqn08kRTUIxPLYju9hExI0cR1ESX+P5tEv5yv0q0UZcisRTw0VB8iUWDIph2LdY1i5Dc8PIvuaWMRNCw3vnKg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/babel-preset@0.83.10': + resolution: {integrity: sha512-wTZWvs5cUQqr2qBAoJNKUy6IBH7wqPAJdxTC834S/7vBqtXypYHxDAFzYXkIh8pRTC86IBYxyc2IrBYHnB8O2g==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + '@react-native/babel-preset@0.83.6': resolution: {integrity: sha512-4/fXFDUvGOObETZq4+SUFkafld6OGgQWut5cQiqVghlhCB5z/p2lVhPgEUr/aTxTzeS3AmN+ztC+GpYPQ7tsTw==} engines: {node: '>= 20.19.4'} @@ -2452,14 +2475,14 @@ packages: peerDependencies: '@babel/core': '*' - '@react-native/codegen@0.83.6': - resolution: {integrity: sha512-doB/Pq6Cf6IjF3wlQXTIiZOnsX9X8mEEk+CdGfyuCwZjWrf7IB8KaZEXXckJmfUcIwvJ9u/a72ZoTTCIoxAc9A==} + '@react-native/codegen@0.83.10': + resolution: {integrity: sha512-rTcuuwRDPLrBmhXc9vAr2gispQFCEqd2WVPh2+N5eV80p8tf9mHy7CoFnmPy8A8csK6HGlANaD9SMPvccQjh4g==} engines: {node: '>= 20.19.4'} peerDependencies: '@babel/core': '*' - '@react-native/codegen@0.83.9': - resolution: {integrity: sha512-fUliGYOD1D/hS4pZMK+YyGb01DxQQNUTjL+i2iL6elt2AncXoYMWNxLT/AMT38jImxI4FbKyH4JO+mL2+t5yuA==} + '@react-native/codegen@0.83.6': + resolution: {integrity: sha512-doB/Pq6Cf6IjF3wlQXTIiZOnsX9X8mEEk+CdGfyuCwZjWrf7IB8KaZEXXckJmfUcIwvJ9u/a72ZoTTCIoxAc9A==} engines: {node: '>= 20.19.4'} peerDependencies: '@babel/core': '*' @@ -2470,8 +2493,8 @@ packages: peerDependencies: '@babel/core': '*' - '@react-native/community-cli-plugin@0.83.9': - resolution: {integrity: sha512-i8WhXYSEIB7kq99n6ZROI1lCckVEwz+Ti/oAT34UUU494MuSvZfd0UWEQ5cFpglPpIKq11KETPwmznHYF6xURg==} + '@react-native/community-cli-plugin@0.83.10': + resolution: {integrity: sha512-7QmZ7FLAIJbYjgxILBUE1k71lQB6atXZSLRczKE6Iti+BO3XHNiDSCZxuxUkYUJI0V/0kCbO/M8/a5zqHNu+Rw==} engines: {node: '>= 20.19.4'} peerDependencies: '@react-native-community/cli': '*' @@ -2482,36 +2505,24 @@ packages: '@react-native/metro-config': optional: true - '@react-native/debugger-frontend@0.83.6': - resolution: {integrity: sha512-TyWXEpAjVundrc87fPWg91piOUg75+X9iutcfDe7cO3NrAEYCsl7Z09rKHuiAGkxfG9/rFD13dPsYIixUFkSFA==} + '@react-native/debugger-frontend@0.83.10': + resolution: {integrity: sha512-AlSOMdXoaSXi4O82f3APvw14e+EfrEvwPerfH2AI3JUrD/yQjFtbIxeyRPd89/MlKIbZU4cwyVFqj96bj39J5g==} engines: {node: '>= 20.19.4'} - '@react-native/debugger-frontend@0.83.9': - resolution: {integrity: sha512-LEOJrHvVWnjHC+emTyybeHkrInrJBnchk3VEhW5qGMWhW3vSM421CrZSCKAvzy+fDg/viufwBfIJvwTdk066CA==} + '@react-native/debugger-shell@0.83.10': + resolution: {integrity: sha512-hk9xFI9H412XSX1lpVuKrnxUQe3zIPKxFceYPUwx2L5aZQQ/yjypWkLs+LLldV6eh93B2sBnZbns1oFSE3LQNw==} engines: {node: '>= 20.19.4'} - '@react-native/debugger-shell@0.83.6': - resolution: {integrity: sha512-684TJMBCU0l0ZjJWzrnK0HH+ERaM9KLyxyArE1k7BrP+gVl4X9GO0Pi94RoInOxvW/nyV65sOU6Ip1F3ygS0cg==} + '@react-native/dev-middleware@0.83.10': + resolution: {integrity: sha512-V39TcESd9LGzDBs7PYVsx5oE1oGv1dLC0GIyJyEyehZjmOYk5sJ4C0m1ATKPeDE7JhiY8s/p6pNOBNp+NF4FGQ==} engines: {node: '>= 20.19.4'} - '@react-native/debugger-shell@0.83.9': - resolution: {integrity: sha512-vAqDG7+3HOz4VOSfccSNe06C1+evcp2AbMjoYOmOyeJtt5dCdmGUp0FICsnU7iuctsNXWnHqyhks9M0wn7zEzA==} + '@react-native/gradle-plugin@0.83.10': + resolution: {integrity: sha512-DpWzrcmxAEgD/tvy4r4WH10PYJPdfDCvtctVZ2Ez0sHlNYgWI6STfqxeAcZhU84hMhNsTec3IHDxNJ2cG8xPjQ==} engines: {node: '>= 20.19.4'} - '@react-native/dev-middleware@0.83.6': - resolution: {integrity: sha512-22xoddLTelpcVnF385SNH2hdP7X2av5pu7yRl/WnM5jBznbcl0+M9Ce94cj+WVeomsoUF/vlfuB0Ooy+RMlRiA==} - engines: {node: '>= 20.19.4'} - - '@react-native/dev-middleware@0.83.9': - resolution: {integrity: sha512-4rW8KGkfqmZ5x1CTr+GrPBTdLG58UNkkJNQ8Dd9xdiVrZ/94sYKHm4HOo+UKTyOP0SNbZpZejDrf/2JNiqNL4Q==} - engines: {node: '>= 20.19.4'} - - '@react-native/gradle-plugin@0.83.9': - resolution: {integrity: sha512-v+iag7ft+fBRP54GthOiR70qrp0azgvW8PhNg0KFYw52xin09LoC0rk96CY+Hj5M1oGoQovrk0bdji7ipH2pGg==} - engines: {node: '>= 20.19.4'} - - '@react-native/js-polyfills@0.83.9': - resolution: {integrity: sha512-6+OdNC3GSgNI3L31zo730AxdI3eXjwD74k0M11gpvXKTOX/NQuXe3On+K4yLFokD2BFr8bL6XaqxCniCUQ3Q+Q==} + '@react-native/js-polyfills@0.83.10': + resolution: {integrity: sha512-q28LKHga5lf2ZX4u1T8Bj5RXqyzOBRWSXVjCCdczj/oacAVZPUrandGC1E9fR35fujyb3ZCqZbIQCvs8MhsTNA==} engines: {node: '>= 20.19.4'} '@react-native/js-polyfills@0.85.2': @@ -2531,14 +2542,11 @@ packages: '@react-native/normalize-colors@0.74.89': resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} - '@react-native/normalize-colors@0.83.6': - resolution: {integrity: sha512-bTM24b5v4qN3h52oflnv+OujFORn/kVi06WaWhnQQw14/ycilPqIsqsa+DpIBqdBrXxvLa9fXtCRrQtGATZCEw==} + '@react-native/normalize-colors@0.83.10': + resolution: {integrity: sha512-dWgqcxaBy27oLx9tndcTF0917vbLOOstyNjYD58J6Z7YxkEZSaKG6+A+3I1KV6O1Xg2D69QThp4t6ezoC3NiGA==} - '@react-native/normalize-colors@0.83.9': - resolution: {integrity: sha512-GSXSvH+siDF2z+XtoF3Kk6zRFMWhGIpfq9nalBd4DSV97g5yNRQ5Htm2fpq7vBYNN+hVgvGZf7rRqnjn8bvfHg==} - - '@react-native/virtualized-lists@0.83.9': - resolution: {integrity: sha512-fZ84faVUANrBU7GfL1wPSkGkn5cnCPVXxAwutKit1S5i8hlfwCnt0gE9Fu/0fpAIeuGxHVed00w2xxDVXyLxKQ==} + '@react-native/virtualized-lists@0.83.10': + resolution: {integrity: sha512-KNX6jCYcCnOKfoJyGMcgDrAVaQXOuNymBi2UC9sf2msEmgkrGgoWa+eKiATqaCgN44UFKlJIuNj4wUPTCWzZ0Q==} engines: {node: '>= 20.19.4'} peerDependencies: '@types/react': ^19.2.0 @@ -2982,17 +2990,64 @@ packages: resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-wny2pgKjGbiZtnOIHVa3tXC1UfDqxNEFzyPGmiqybedG8hipG2Nfp0l5UxbaKCjkLacUpH/W5bP2hBOMVhCOzg==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-Afc7M5zOwo+GpfcYwz5Z8HMB2tPVsui7nNIqEuuFB73MPdVqNn/Wmpe4tP4MRri0AtJnJknoHBaTJ/VDAp/Jhw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-iITBa2WjjTI5N9t5l7Z4KoOSI+2zBlhbvFzsD/f8qX8QoKjz/Y4DPyBDgezYi8nkqjjksbgSOJ3/ykzhwrB9cg==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-hJm/UOqZTr9FHmR7uNm8VGX4oKtfWk0Jem0zPeJFNC8ckGUfSBueyiEYMZB+XmRc1aG4x1E46y3CplP4CLHvGQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-du0dzi6y97Po5vDNdPJTyyijHCpaS22JLRnKZEJXBDaO9gCIymOv/5QQokFRuOlQm0bWl3i9PF4OVdGP6uAOQA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-SsAwfhyHJ1akgBc+99z4+hwdbHsdWaKB8EwCNIMA6JfSLMeUjffrYvxu+vfMyxVtOVOz7RrRXRoiDiu4a2sCtg==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-DL4u27stv0fo71sVhOzHSwE+YMZsbBijVI+kg5dLDLilSH79WFTJ8RSQ46vJrCMt+Gjlv/JOZP1PuLJDfioYeQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20260707.2': + resolution: {integrity: sha512-oUGp+Rep/hqMhPunyinsALUwSlzHINSxitifPiSaeqoKOKD2OlR9NE3TaPqwsl4NlGslsOSUXI1JotWQzpYCPg==} + engines: {node: '>=16.20.0'} + hasBin: true + '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} '@upsetjs/venn.js@2.0.0': resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} - '@vitest/expect@4.1.9': - resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@4.1.9': - resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3002,20 +3057,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.9': - resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.9': - resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.9': - resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.9': - resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.9': - resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} @@ -3079,6 +3134,11 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agent-cli-detector@0.1.7: + resolution: {integrity: sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==} + engines: {node: '>=18.18'} + hasBin: true + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} @@ -3259,8 +3319,8 @@ packages: expo-widgets: optional: true - babel-preset-expo@55.0.23: - resolution: {integrity: sha512-oY+UFcXRLtidYp0JcttzxV5Qxx7KBjBJIShalb+hk4TQoLYafJr4ubpYajLwt7BBgAIVwBdxltKeYeNYXYf02A==} + babel-preset-expo@55.0.25: + resolution: {integrity: sha512-P/CaG4kvSzd8Pb1CiS8m6C9XCwuLptaaw+F/GfDNGUkuF3/DlYCkdj4Ogq1mJ5OJ80qdlaY9TzxB28CrL/dIqg==} peerDependencies: '@babel/runtime': ^7.20.0 expo: '*' @@ -4125,6 +4185,7 @@ packages: eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -4184,25 +4245,25 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - expo-application@55.0.14: - resolution: {integrity: sha512-NgqDIt3eCf4aVLp1L6AcEanCYoyJeuBsGrgGSzOIvxAsOvp5X3SYKW3ROgpKUnLQEKMWlzwETpjsUGszcqkk8g==} + expo-application@55.0.19: + resolution: {integrity: sha512-RFer4T46/OaIkNQEweA9PQj6xlXKor71IPNydWxlupx/XG05Yv/269HJJ3Q9zejdY9M7R3jTeTlAYYmXwbLBgA==} peerDependencies: expo: '*' - expo-asset@55.0.17: - resolution: {integrity: sha512-pK9HHJuFqjE8kDUcbMFsZj3Cz8WdXpvZHZmYl7ouFQp59P83BvHln6VnqPDGlO+/4929G0Lm8ZUzbONuNRhi9w==} + expo-asset@55.0.20: + resolution: {integrity: sha512-BpybBESZj8WxW/WXuQhiY8D1azkJtxLuteIfprokJw0uU5r/g7cD+vzrzKJSlE4hhUlKeUGsoKzSK0nSJJ2sMQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-build-properties@55.0.13: - resolution: {integrity: sha512-UYZhUKyh7YQhbJdkBvo68WUQ7fOtZeSV7F8kfYkjEiN/ADRHG0WfEIiddvGfi9cH/5iwpptv/+Lu5cx6uvfegA==} + expo-build-properties@55.0.18: + resolution: {integrity: sha512-LLTuab2S4Gv9dYjolBF/noRAUosa9Fu1o374yoQ7WD+NLWP8rn3fUd5ciKlx7f702JqO7tDJB2+BUjTwtgciCg==} peerDependencies: expo: '*' - expo-camera@55.0.18: - resolution: {integrity: sha512-Us/7JV6O1lHpLBGKJnK2s8gzmPcmMVJSV5586DBeO7x7AXzmvvVGtH+0nJRVIBE3MNzGzGWyfgievjr8QlE7dA==} + expo-camera@55.0.23: + resolution: {integrity: sha512-Qra5QIZv0BOXLLXNfQlOW8NLUx3gLiWKCfpLeguiOwXY6XPj9xIE3AfbrxGa27/KohgrtHy1sgsnLeJB76OGjA==} peerDependencies: expo: '*' react: '*' @@ -4212,31 +4273,31 @@ packages: react-native-web: optional: true - expo-clipboard@55.0.13: - resolution: {integrity: sha512-PrOmmuVsGW4bAkNQmGKtxMXj3invsfN+jfIKmQxHwE/dn7ODqwFWviUTa+PMUjP3XZmYCDLyu/i0GLeu7HF9Ew==} + expo-clipboard@55.0.17: + resolution: {integrity: sha512-wVWLvBfsFE3W3MBBSYAjwybkV40XowK65R9PDqfiuU2F9h7grKVjCjWD6FE7I4goZo0hFM8MfZNP+7XOdJMYiQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-constants@55.0.16: - resolution: {integrity: sha512-Z15/No94UHoogD+pulxjudGAeOHTEIWZgb/vnX48Wx5D+apWTeCbnKxQZZtGQlosvduYL5kaic2/W8U+NHfBQQ==} + expo-constants@55.0.17: + resolution: {integrity: sha512-t0SNWmXTjXPCHzjNsv1Okjaj8SpXQcUjDPtYDqvofDS+BhAsvlKNmwaaWXvduBjjmmmJWNH8q1/x9IWQ+upg8g==} peerDependencies: expo: '*' react-native: '*' - expo-crypto@55.0.14: - resolution: {integrity: sha512-TfAADBGZNNv9OOmdKFJCz54wDj87ufxtzQNSY+Roycpm8e5tuCnDIL7EjqUOmNTGH99Jj8ftPGFt4KGG2Ii2fg==} + expo-crypto@55.0.19: + resolution: {integrity: sha512-Ip1jQ5GphvrC4Ls5osAmIapi+JZXOqRJYaaMxTFWpkhssNUq88oP45pWGv2uU2K/Ci6j7iLDJzU8eN3v+B7jrA==} peerDependencies: expo: '*' - expo-dev-client@55.0.35: - resolution: {integrity: sha512-DN50x9gqWYAfnJpxgiJm3zK2bFvDhxJ5JjFq0wFot7o4knZ7H3BVwiL6zZMHG29g6gfxdgpzGG69WPiSR/Ipgg==} + expo-dev-client@55.0.39: + resolution: {integrity: sha512-/AesdrrjyaGPALr7jGRZcHlijzF2pNiFBBwiaCZYTlJsWLlmgw90SHjcZ81DXVb/UaM5tO1903T1lPBY+dUdcA==} peerDependencies: expo: '*' - expo-dev-launcher@55.0.36: - resolution: {integrity: sha512-Dn2om4J71aavWqi1jLzK3QlGZjDiFv7nIBZkQyzy2zW62IOD9kLwOOvHHj07Ra/6n9cqFEpNYzwpPkR7KHuYZA==} + expo-dev-launcher@55.0.40: + resolution: {integrity: sha512-tzv3D1xotXroTSiu6EHVldZ2rr/LEW82VYZXZbqNeR15GufHm+Jed6gc3o2V6WV5UMeBonj1d3KhF/Zs2YdvNQ==} peerDependencies: expo: '*' @@ -4245,24 +4306,18 @@ packages: peerDependencies: expo: '*' - expo-dev-menu@55.0.30: - resolution: {integrity: sha512-uwDI4cEPzpRemf06Ts5O41azJcz8BBcE6QOkNaTX8JlzdJ05eq9jWxmbA1WhoSoE5C+NFo8njHSvmHqUqTpOng==} + expo-dev-menu@55.0.34: + resolution: {integrity: sha512-FowMkhG32iw1qpKSWJI5wl/27DaaJbbMEtK6MQFMGcEgbk7UV42jWDd1AUuUUaf4Euxpgn36KWpG+blh/2gaHA==} peerDependencies: expo: '*' - expo-document-picker@55.0.13: - resolution: {integrity: sha512-IhswJElhdzs3fKDEKW8KXYRoFkWGEsXRMYAZT46Yo56zqqy8yQXrczo33RSwD2hFzNQBdLT97SJL9N311UyS3g==} + expo-document-picker@55.0.17: + resolution: {integrity: sha512-tyrPB+k3lTI03umNP8cc912yZF7tgyo9v/+rEeW9h/u0fmMJAvegyaQl/YNW2MeKpjYa4+WwiLBGXVj54XHDog==} peerDependencies: expo: '*' - expo-file-system@55.0.19: - resolution: {integrity: sha512-c4smCbMqELLI3YQrGpw21MwZIREXM2e53vQD/+KWQcae1q+hgw8J2TroEqcQ/jVOtFpZYVvyVfgu4HDKNEKmNw==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-file-system@55.0.23: - resolution: {integrity: sha512-XNV/NaPc7Tvd2JIsWkPW8s2vfJUI/Oe4UMX9TmOGpc6cn5BckDw/nn2Qre9lq4btT4FWHJw4SAOHmATShLC0og==} + expo-file-system@55.0.26: + resolution: {integrity: sha512-KBOQWqxumCxJBN29Lu13QpccwAhcjsgDYCJSVVjfGydaK/UbEkH/1rT/WZmdfoZ4G8mUJlfRbWfnJtfHUXxsdw==} peerDependencies: expo: '*' react-native: '*' @@ -4281,8 +4336,8 @@ packages: react: '*' react-native: '*' - expo-haptics@55.0.14: - resolution: {integrity: sha512-KjDItBsA9mi1f5nRwf8g1wOdfEcLHwvEdt5Jl1sMCDETR/homcGOl+F3QIiPOl/PRlbGVieQsjTtF4DGtHOj6g==} + expo-haptics@55.0.18: + resolution: {integrity: sha512-bEH0bf5bBGn7U2eTZVdiXBUk4vTfNGbfv9/9PCYLg3gL7L/WE2g8WKs2vYg1B4/BDSucyO8prZofH3IgvLJojQ==} peerDependencies: expo: '*' @@ -4291,18 +4346,18 @@ packages: peerDependencies: expo: '*' - expo-image-manipulator@55.0.17: - resolution: {integrity: sha512-lTYhmXejHnMp+vjFID0Q/jD+Qic3U9OP4qw3tCVHCVp4TTmx9hbifTIN0hmw02ak7LsBkxuYnP+uglvUKgJAzA==} + expo-image-manipulator@55.0.21: + resolution: {integrity: sha512-BlVl692hVDKuWzOCnbUsfp1u0XqujOABm/Kv3ISMg0qRMchvD6vUSJ/XOIj80+6B9CCm1hNgklgeJ0SIEHiCVQ==} peerDependencies: expo: '*' - expo-image-picker@55.0.20: - resolution: {integrity: sha512-lfWt/0rPWdKz8AdDEGmGHZIJSNlVc720Dlx5bfou10FU16ZV5wAbTU63nm2jkXd8hbXke4a/2Ha1dzxCVA+LQQ==} + expo-image-picker@55.0.24: + resolution: {integrity: sha512-scbtvQIgiqiOxQx/lFEocJkWPzYANHjwFLnzfKjdZNWh3RJjjMmtHaEoeu7lM9RzqE3EwF+JQecgy+FATXNfiQ==} peerDependencies: expo: '*' - expo-image@55.0.10: - resolution: {integrity: sha512-We+vq/Z8jy8zmGxcOP8vrhiWkkwyXFdSks8cSlPi0bpu6D0Ei6l9Nj2xHWCD+yoENh92aCEe1+QRujAwXbogGA==} + expo-image@55.0.11: + resolution: {integrity: sha512-PVIBYQJW/h1f6Zb9xnoWlgfqyOPVm2yb6eo6ZogaKbvMrhb/Q/fiERbagi4oqmR6IPljWPEpkXXQyFBUh7TjpQ==} peerDependencies: expo: '*' react: '*' @@ -4321,14 +4376,14 @@ packages: expo: '*' react: '*' - expo-linking@55.0.15: - resolution: {integrity: sha512-/RQh2vkNqV8Bim9Owm/evVqn2fqTvCDYHkpYPoSKbLAdydSGdHC2xZNw7Odl4wu1i1/3L4Xz//LKd3NsPWYWBQ==} + expo-linking@55.0.17: + resolution: {integrity: sha512-rc41rUbFYdJ4IdPxWQiTDtkOlEbtYQkvsCASzW1pqskfRShAd4tYyyAw1BTez3Cq1IgWkK3wcGR+HbFdzZ7ImQ==} peerDependencies: react: '*' react-native: '*' - expo-manifests@55.0.17: - resolution: {integrity: sha512-vKZvFivX3usVJKfBODKQcFHso0g38zlGbRGqGAppz+il0zKvG6umpJ47OZbzLod7iJpjd+ZDD2AGuOxacixonA==} + expo-manifests@55.0.21: + resolution: {integrity: sha512-Eu27Ia6v2Ev4i7AoswypTcqhWTKmyjd8t8cwznK3HkDQqhfHsAQIeBxSwiLmErS25iD5NsQ4C3+w/2TZdLABhQ==} peerDependencies: expo: '*' @@ -4336,8 +4391,8 @@ packages: resolution: {integrity: sha512-gtFQzs6wduZxYo4/1udcVLANDvQbVUVFjK1xJjgtZuUBlbJ+xFjQg5wOsQaffUDO3kqrG+DRXt1ihSxK72Wqkg==} hasBin: true - expo-modules-autolinking@55.0.24: - resolution: {integrity: sha512-A0OyMbTPZqibYrwqj98HFYTNSvl4NSS4Zt+R5A8qiAx3nM0mc81e6Iqw7Wl4J8M/t36lJ+cT3WuVTz5Oszj6Hw==} + expo-modules-autolinking@55.0.27: + resolution: {integrity: sha512-gBRONXQT41PwfsQgeZfFlaeK+zrYMYjRMgxocecnQuSXEm7wCTqD8SsTJmWAf3SDayMQGDZFBlMODeVEnv8FmA==} hasBin: true expo-modules-core@55.0.25: @@ -4350,29 +4405,29 @@ packages: react-native-worklets: optional: true - expo-network@55.0.14: - resolution: {integrity: sha512-Sy544zTPjVh+tbOLUOU8fBX87oRSrNQqUZY6TLO0w0WF/QTNb7yxlwRh6v6wfKKRg9xpZypTIIEtdG/s6q8ZQA==} + expo-network@55.0.18: + resolution: {integrity: sha512-zHKgRbTbPAN/TYbnV4r2DGlTvq5DG26n/N0S/MF41i3S/kcU6fad/YNgdkixmXt2JFNOCfT3OnouV2q7OyYAWg==} peerDependencies: expo: '*' react: '*' - expo-notifications@55.0.22: - resolution: {integrity: sha512-Rwvsp/lAEXfDYBxkQZpaLF9ZB25cJ/yfHhD/ESclbPesN0nbQBZ/5rGb1xS/saANtkStbEGfDlA80uHh2zEpsA==} + expo-notifications@55.0.27: + resolution: {integrity: sha512-Qquo8zytHPR4Rj819KwghUqvdf2RJG8+S8Y3DQ+4wUZgRFdWqNnh8IX9IhcdITTGr/Ei0I9LzI0BKG4qyO9ubw==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-router@55.0.14: - resolution: {integrity: sha512-rOn/wosp2hAPM+O2o41hnarbP5Zqv9UkHWa31KoSoiOme1tpmZd2yc93XtRAtzP0P5E5xzqq7a2rbEAarpP5XA==} + expo-router@55.0.18: + resolution: {integrity: sha512-KfGkHUgPsstqYD5kEyUtCKIMzPsKeuS+4C+xZ8sj8lEmL1Liy4JYuDoDSEhBVXWoQN82rYAqbBKgr9n+G1mk+g==} peerDependencies: - '@expo/log-box': 55.0.12 - '@expo/metro-runtime': ^55.0.11 + '@expo/log-box': 55.0.13 + '@expo/metro-runtime': ^55.0.12 '@react-navigation/drawer': ^7.9.4 '@testing-library/react-native': '>= 13.2.0' expo: '*' - expo-constants: ^55.0.16 - expo-linking: ^55.0.15 + expo-constants: ^55.0.17 + expo-linking: ^55.0.17 react: '*' react-dom: '*' react-native: '*' @@ -4398,21 +4453,17 @@ packages: react-server-dom-webpack: optional: true - expo-secure-store@55.0.13: - resolution: {integrity: sha512-I6r0JNO1Fd4o0Gu7Ixiic7s89lqgdUHq17uBH9y1f/AntoyKn71TdtYJH82RgfsBbu5qNVzrwImmvlANyOlITQ==} + expo-secure-store@55.0.18: + resolution: {integrity: sha512-shKZYQf7/KA45Z3oEIXUkXdrfRNFxsc+fJC182bbpuKqS4nLPZslsJUqruQ937Zkkbev126N/QJv+zmd6FpZjA==} peerDependencies: expo: '*' - expo-server@55.0.11: - resolution: {integrity: sha512-AxRdHqcv0H1g4s923vu+5n1Nrhne23bjXbP+Vl7+Lwfpe7MG9PuU1IS95IJK6a+7BVV1mRN6QlZvs8Yv7EEXNQ==} + expo-server@55.0.12: + resolution: {integrity: sha512-yuNHbxobUKCXWn9Z/H+lgYk6heXEFub6q1h8Yo9kCLxgL2afluWZ/YylbtxgHgmFwDVUmi6milQYfL+wwQMlzw==} engines: {node: '>=20.16.0'} - expo-server@55.0.9: - resolution: {integrity: sha512-N5Ipn1NwqaJzEm+G97o0Jbe4g/th3R/16N1DabnYryXKCiZwDkK13/w3VfGkQN9LOOaBP+JIRxGf4M8lQKPzyA==} - engines: {node: '>=20.16.0'} - - expo-splash-screen@55.0.20: - resolution: {integrity: sha512-WI5T0dutiZhxsqlF+jhEP4JRpQNILLlP8IpmKehsnV53Cncv6AQrKE7y1sOWwDyC2m2GBufZ/Vwam1RMt2EfmA==} + expo-splash-screen@55.0.25: + resolution: {integrity: sha512-Jl3VPbNqbgGjXlkH93hi4Y4p6GB5DasLNbpL2Gb4kl8grujKaIGi4rXL25qYbYxIzefSlt96NqG9czanxxooPg==} peerDependencies: expo: '*' @@ -4422,8 +4473,8 @@ packages: react: '*' react-native: '*' - expo-symbols@55.0.8: - resolution: {integrity: sha512-Dg6BTu+fCWukdlh+3XYIr6NbqJWmK4aAQ6i6BInKnWU0ALuzVUJcMDq8Lk9bHok2hOh3OhzJqlCqEoBXPInIVQ==} + expo-symbols@55.0.9: + resolution: {integrity: sha512-F85C/8ExQjd2gYjasLVKMT8wPj+1+19TVTqg4jAeVjVZklqiQtLO72io9Ji1xAjYNgmDeUI0diVHlFMMTC4Ekg==} peerDependencies: expo: '*' expo-font: '*' @@ -4435,8 +4486,8 @@ packages: peerDependencies: expo: '*' - expo@55.0.27: - resolution: {integrity: sha512-uB8fbowkb/Xel2/x4b+cFfg76GGb2lhgaPVdm/ago+QL/852VJP+bUU6LzQVszQFmCTMHCJyrQ4l8enThCnfxw==} + expo@55.0.30: + resolution: {integrity: sha512-BgarG0CY16G25wMjCHw+0FuY3RfsJ8Yn8T/aENKKhnomrHOlG0cOcwJqia7WQDCpf620CJJ8XMOBBizOGDkLfw==} hasBin: true peerDependencies: '@expo/dom-webview': '*' @@ -4467,6 +4518,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fastdom@1.0.12: + resolution: {integrity: sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==} + fb-dotslash@0.5.8: resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} engines: {node: '>=20'} @@ -4651,8 +4705,8 @@ packages: hachure-fill@0.5.2: resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} - happy-dom@20.11.1: - resolution: {integrity: sha512-XSt8tMzbW9ymE7687xztkO1ckR7qJNQ3LywY9vlYGhGi3zXrGBHuUo2Cl1ztZaICW+1eAGdkLbj6iwVqDT33kg==} + happy-dom@20.11.8: + resolution: {integrity: sha512-TeAoM8pTDKNVcP5z3MptRTb7UH9q126GrjTFOgormgA19tmT30JTiIxb1CVXs7xljpItypUp/yHSPFD4QRHMsQ==} engines: {node: '>=20.0.0'} has-bigints@1.1.0: @@ -5427,13 +5481,17 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - mermaid@11.16.1: - resolution: {integrity: sha512-TQsq6u22fAn3rek5VOubrhKPo1g5hwC3FXUN9hiyupTckcYiGuuKGkNQrKYwGJkXUxZdojwRG46gsSCFZMDp4g==} + mermaid@11.17.2: + resolution: {integrity: sha512-V6K3C8EBdEsPFZXSKMJe6ppQOENxuHARr9GvHX4hh47lAbhMRD9qf4oEK7LoaRQxULMa80/qt5gHO73aCleBBg==} metro-babel-transformer@0.83.7: resolution: {integrity: sha512-sBqBkt6kNut/88bv+Ucvm4yqdPetbvAEsHzi3MAgJEifOSYYzX5Z5Kgw3TFOrwf/mHJTOBG2ONlaMHoyfP15TA==} engines: {node: '>=20.19.4'} + metro-babel-transformer@0.83.8: + resolution: {integrity: sha512-tnn0J5wzgTgTx2OJy3Cwr1y79bJz4eNgFQd+2HENOs5Vz6QOMnt05z7J+BedIo9wIbpEa0iN9U1nerxyvMRE9g==} + engines: {node: '>=20.19.4'} + metro-babel-transformer@0.84.4: resolution: {integrity: sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5442,6 +5500,10 @@ packages: resolution: {integrity: sha512-W1c2Nmx8MiJTJt+eWhMO08z9VKi3kZOaz99IYGdqeqDgY9j+yZjXl62rUav4Di0heZfh4/n2s722PqRL1OODeg==} engines: {node: '>=20.19.4'} + metro-cache-key@0.83.8: + resolution: {integrity: sha512-I38PtcjT4crS5HY9UQ8i6z8S7tJ2WewtPGr/OwS6FcLKfy5T/1hlTaFw+wozUZkEtNpR6Gc0oJuvuKCbSoSN5A==} + engines: {node: '>=20.19.4'} + metro-cache-key@0.84.4: resolution: {integrity: sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5450,6 +5512,10 @@ packages: resolution: {integrity: sha512-E9SRePXQ1Zvlj79VcOk57q7VC7rMHMFQ+jhmPHBiq+dJ0bJB5BL87lWZF6oh5X76Cci5tpDuQNaDwwuSCToEeg==} engines: {node: '>=20.19.4'} + metro-cache@0.83.8: + resolution: {integrity: sha512-aogMG5WbKzW5000otNjYrS9hIoORzkCI1faPJK+vxQLaf2BorJKBBFe/jl2Tfsi1mZUglS2EBuBt8B3JB7MYDQ==} + engines: {node: '>=20.19.4'} + metro-cache@0.84.4: resolution: {integrity: sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5458,6 +5524,10 @@ packages: resolution: {integrity: sha512-83mjWFbFOt2GeJ6pFIum5mSnc1uTsZJAtD8o4ej0s4NVsYsA7fB+pHvTfHhFrpeMONaobu2riKavkPei05Er/Q==} engines: {node: '>=20.19.4'} + metro-config@0.83.8: + resolution: {integrity: sha512-crNbNy+/B4tCne2+HjUshwvC57gNBQj+V9fFSy3lHH2RlKcLHib3Mil/SfTX8Pfh2fCY5pPuSu2OKa7YiadB+Q==} + engines: {node: '>=20.19.4'} + metro-config@0.84.4: resolution: {integrity: sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5466,6 +5536,10 @@ packages: resolution: {integrity: sha512-6yn3w1wnltT6RQl7p7YES2l95ArC+mWrOssEiH8p5/DDrJS65/szf9LsC9JrBv8c5DdvSY3V3f0GRYg0Ox7hCg==} engines: {node: '>=20.19.4'} + metro-core@0.83.8: + resolution: {integrity: sha512-NTyOUOQaQKvQgJG9VI2ymN6KTM7gHEqkVFhkPc9bK4BsHSTz/EaXuFBXtC+wtwINLeH9tbusL/jfsSmdEmuU7A==} + engines: {node: '>=20.19.4'} + metro-core@0.84.4: resolution: {integrity: sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5474,6 +5548,10 @@ packages: resolution: {integrity: sha512-+j0F1m+FQYVAQ6syf+mwhIPV5GoFQrkInX8bppuc50IzNsZbMrp8R5H/Sx/K2daQ3YEa9F/XwkeZT8gzJfgeCw==} engines: {node: '>=20.19.4'} + metro-file-map@0.83.8: + resolution: {integrity: sha512-+W++EUuzEXIfWQEFTWQMVThzhWbnJL4gRNJ9WSHzIAM5pT7gsprUxo9+2hrfirURm/TLvrKwhq37oCECJcDSyQ==} + engines: {node: '>=20.19.4'} + metro-file-map@0.84.4: resolution: {integrity: sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5482,6 +5560,10 @@ packages: resolution: {integrity: sha512-MfJar2IS4tBRuLb9svwb0Gu5l9BsH+pcRm8eGcEi/wy8MzZinfinh5dFLt2nWkocnulIgtGB5NkFDdbXqMXKhQ==} engines: {node: '>=20.19.4'} + metro-minify-terser@0.83.8: + resolution: {integrity: sha512-7tU0J5/c7LZaZJwTlOb1xq0NepTFvGzRxigDhZOq4jSE6g0BRHmBqe7XvLH3WcRiJNGy+eshcZr34RpMjb6mmg==} + engines: {node: '>=20.19.4'} + metro-minify-terser@0.84.4: resolution: {integrity: sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5490,6 +5572,10 @@ packages: resolution: {integrity: sha512-WSJIENlMcoSsuz66IfBHOkgfp3KJt2UW2TnEHPf1b8pIG2eEXNOVmo2+03A0H17WY2XGXWgxL0CG7FAopqgB1A==} engines: {node: '>=20.19.4'} + metro-resolver@0.83.8: + resolution: {integrity: sha512-piU0NVTI9i37YztDVF5rtn9uxP3NebVT0xZM9NKJ9z0jbigrctUQksi3NoYIeJMvL6Wn2dgAehpcmmnfn+gUwA==} + engines: {node: '>=20.19.4'} + metro-resolver@0.84.4: resolution: {integrity: sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5498,6 +5584,10 @@ packages: resolution: {integrity: sha512-9GKkJURaB2iyYoEExKnedzAHzxmKtSi+k0tsZUvMoU27tBZJElchYt7JH/Ai/XzYAI9lCAaV7u5HZSI8J5Z+wQ==} engines: {node: '>=20.19.4'} + metro-runtime@0.83.8: + resolution: {integrity: sha512-f7FfeM0pamq8vrvs8aO9KvIUabbUKe0WkHFpLt6Q9yIIIsORqNFwlgJeHGraOFPU7Cxqj5yLXkJu5bT1uwDXvw==} + engines: {node: '>=20.19.4'} + metro-runtime@0.84.4: resolution: {integrity: sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5506,6 +5596,10 @@ packages: resolution: {integrity: sha512-JgA1h7oc1a1jydBe1GhVFsUoMYo3wLPk7oRA32rjlDsq+sP2JLt9x2p2lWbNSxTm/u8NV4VRid3hvEJgcX8tKw==} engines: {node: '>=20.19.4'} + metro-source-map@0.83.8: + resolution: {integrity: sha512-60Uor7bM+KsVewLkLCcZfkPFCbqjPDdoSmeBuT3+ye+ac80BuLWbbR8DpyxWpUqQeZPdaAT5ZqFgDIs8BNEcVA==} + engines: {node: '>=20.19.4'} + metro-source-map@0.84.4: resolution: {integrity: sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5515,6 +5609,11 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + metro-symbolicate@0.83.8: + resolution: {integrity: sha512-ZLrbqOqQ+m+Mpv7zo65XEXkNqVYvgUbY7tIsb9e1zSSmU/4C3D6DjaJvRHqcAdl0mkg8TI/csKooAEa5xcZNwg==} + engines: {node: '>=20.19.4'} + hasBin: true + metro-symbolicate@0.84.4: resolution: {integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5524,6 +5623,10 @@ packages: resolution: {integrity: sha512-Ss0FpBiZDjX2kwhukMDl5sNdYK8T/06IPqxNE4H6PTlRlfs9q11cef13c/xESY/Pm4VCkp1yJUZO3kXzvMxQFA==} engines: {node: '>=20.19.4'} + metro-transform-plugins@0.83.8: + resolution: {integrity: sha512-9JRPkvi+m0QH2Y/w5RjCF9mHqOUNFpMFLDDLhKUjhcKESh8Wm3HKDdHXHVldTN1lTToCIabv81nF0zyJzKEJ5g==} + engines: {node: '>=20.19.4'} + metro-transform-plugins@0.84.4: resolution: {integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5532,6 +5635,10 @@ packages: resolution: {integrity: sha512-UegCo7ygB2fT64mRK2nbAjQVJ1zSwIIHy8d96jJv2nKZFDaViYBiughEdu5HM/Ceq0WN3LZrZk3zhl9aoiLYFw==} engines: {node: '>=20.19.4'} + metro-transform-worker@0.83.8: + resolution: {integrity: sha512-Pa2hOfhUmWpI/dmkhsLq8uGyFHK2opoEK7j/YCiRtqNSe0YzzxYguXTNgg8AMiuZfc9LPcB1AhGENS10O5wcIw==} + engines: {node: '>=20.19.4'} + metro-transform-worker@0.84.4: resolution: {integrity: sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5541,6 +5648,11 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + metro@0.83.8: + resolution: {integrity: sha512-ZbJDJCDlvv0O3QHVbhZkyP2/DtebfEoDZ3wVyYHgu6Uoy6DmmE/bis6lIDBYh+kWPuaueJDegyutPjkIBLtZDQ==} + engines: {node: '>=20.19.4'} + hasBin: true + metro@0.84.4: resolution: {integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5608,8 +5720,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - multitars@1.0.0: - resolution: {integrity: sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg==} + multitars@1.0.2: + resolution: {integrity: sha512-6GwVw5eLi9sThdtlS4PKwC7yRLaf45pYhIEzKBHdKxi+YOXGKFX8acIniH+Uh/+k9mS2lQOupTccjoe5r0/1IQ==} nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} @@ -5679,6 +5791,10 @@ packages: resolution: {integrity: sha512-9M5kpuOLyTPogMtZiQUIxdAZxl7Dxs6tVBbJErSumsqGMuhVSoUbkfeZ3XNPpLpwBBtqY5QDUzGwggLHX3slQg==} engines: {node: '>=20.19.4'} + ob1@0.83.8: + resolution: {integrity: sha512-pk7el+eTOzfSKMAY4QBiiwKzegXn633JQj13y+pW5E5IdS+yV2CfDJ9Hf20K/LKy8nCrP9dAmd7XOk52OJxifA==} + engines: {node: '>=20.19.4'} + ob1@0.84.4: resolution: {integrity: sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5761,8 +5877,8 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - oxfmt@0.52.0: - resolution: {integrity: sha512-nJlYM35F64zTDMecCNhoHNkf+D/eHv7xcjj9XDSj+bFAVtN93m7v8DQMdHd6nDG6Akf/kEYYHmDUBs2Dz27Sug==} + oxfmt@0.65.0: + resolution: {integrity: sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5774,12 +5890,12 @@ packages: vite-plus: optional: true - oxlint@1.71.0: - resolution: {integrity: sha512-U1m1X+C0vDj7DC1e13IoZULzEcPczE7UOMTs8VlZGHUEIUaSTZKo5qkPsQEfzpgnQ29Pea/w3Xntk62UCecxZw==} + oxlint@1.80.0: + resolution: {integrity: sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.22.1' + oxlint-tsgolint: '>=7.0.2001' vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: @@ -5971,10 +6087,10 @@ packages: react-devtools-core@6.1.5: resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - react-dom@19.2.6: - resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} peerDependencies: - react: ^19.2.6 + react: ^19.2.8 react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} @@ -5994,6 +6110,9 @@ packages: react-is@19.2.6: resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==} + react-is@19.2.8: + resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==} + react-native-gesture-handler@2.31.2: resolution: {integrity: sha512-rw5q74i2AfS7YGYdbxQDhOU7xqgY6WRM1132/CCm3erqjblhECZDZFHIm0tteHoC9ih24wogVBVVzcTBQtZ+5A==} peerDependencies: @@ -6006,8 +6125,8 @@ packages: react: '*' react-native: '*' - react-native-reanimated@4.3.0: - resolution: {integrity: sha512-HOTTPdKtddXTOsmQxDASXEwLS3lqEHrKERD3XOgzSqWJ7L3x81Pnx7mTcKx1FKdkgomMug/XSmm1C6Z7GIowxA==} + react-native-reanimated@4.3.4: + resolution: {integrity: sha512-kQJMiDROed3eO+asdXfodDxgsDDIGM/ifnHFAiPsKWxmrcPu+Bz4vO0fg79eyuEmKCeQuDczmn4tkTb4RbSVYA==} peerDependencies: react: '*' react-native: 0.81 - 0.85 @@ -6037,8 +6156,8 @@ packages: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - react-native-webview@13.16.1: - resolution: {integrity: sha512-If0eHhoEdOYDcHsX+xBFwHMbWBGK1BvGDQDQdVkwtSIXiq1uiqjkpWVP2uQ1as94J0CzvFE9PUNDuhiX0Z6ubw==} + react-native-webview@13.16.2: + resolution: {integrity: sha512-4H3ypsaXjxHRFSHX348IdED4kJ5cQGN5DLAaIAasiHENb10xlYx0XTlEFwPJa9PbkzU1IHeiTfvAoisZzGg1gA==} peerDependencies: react: '*' react-native: '*' @@ -6051,8 +6170,8 @@ packages: react: '*' react-native: 0.81 - 0.85 - react-native@0.83.9: - resolution: {integrity: sha512-bTQpaSJBbxOizI8SMNiCR/5aIvfO3ZlXAcWYxg6FmdbfJYCZ0zdUCK9mSZ4patureITGHNU94RXhxDAJhqsO7w==} + react-native@0.83.10: + resolution: {integrity: sha512-4gbmtAyfC0F4jU2hl/l/HZbRIfRl0d5RdHNpJLf7sT/0zhYDEhiFcFk7ii2utl7O8BIHRUmGe/anfWP3DNPTZw==} engines: {node: '>= 20.19.4'} hasBin: true peerDependencies: @@ -6101,13 +6220,13 @@ packages: peerDependencies: react: ^19.2.0 - react-test-renderer@19.2.6: - resolution: {integrity: sha512-GbS6V23YduFTPiWJ5xICbKEjRcqx1Z90js/V5miqhz7qp/d6xSe9Dd6NjSQODFRdzdsqRMPW82E/sFpPRbY5Mw==} + react-test-renderer@19.2.8: + resolution: {integrity: sha512-GHKPaDRaNYU24PHTLG8Bx8VMY9t+qNfxQbt/Yjp7aMWBkKU6766SR0n6TnYu7P5I1MfEuAMUadqiyDHyI4Yy9Q==} peerDependencies: - react: ^19.2.6 + react: ^19.2.8 - react@19.2.6: - resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -6260,11 +6379,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.8.4: - resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} - engines: {node: '>=10'} - hasBin: true - semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -6444,6 +6558,9 @@ packages: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} + strictdom@1.0.1: + resolution: {integrity: sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg==} + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -6555,11 +6672,6 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.46.2: - resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} - engines: {node: '>=10'} - hasBin: true - terser@5.49.1: resolution: {integrity: sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==} engines: {node: '>=10'} @@ -6861,20 +6973,20 @@ packages: yaml: optional: true - vitest@4.1.9: - resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.9 - '@vitest/browser-preview': 4.1.9 - '@vitest/browser-webdriverio': 4.1.9 - '@vitest/coverage-istanbul': 4.1.9 - '@vitest/coverage-v8': 4.1.9 - '@vitest/ui': 4.1.9 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -6988,18 +7100,6 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@7.5.11: - resolution: {integrity: sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@7.5.13: resolution: {integrity: sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==} engines: {node: '>=8.3.0'} @@ -7012,8 +7112,8 @@ packages: utf-8-validate: optional: true - ws@8.21.0: - resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -7054,11 +7154,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.4: - resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} - engines: {node: '>= 14.6'} - hasBin: true - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -7200,7 +7295,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-compilation-targets@7.28.6': dependencies: @@ -7239,7 +7334,7 @@ snapshots: '@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/traverse': 7.29.8 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -7282,8 +7377,8 @@ snapshots: '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -7296,8 +7391,8 @@ snapshots: '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -7325,7 +7420,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-plugin-utils@7.28.6': {} @@ -7363,7 +7458,7 @@ snapshots: '@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 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -7376,8 +7471,8 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -8616,30 +8711,31 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.34': {} - '@expo/cli@55.0.33(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.16)(expo-font@55.0.8)(expo-router@55.0.14)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3)': + '@expo/cli@55.0.36(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.17)(expo-font@55.0.8)(expo-router@55.0.18)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 55.0.18(typescript@6.0.3) - '@expo/config-plugins': 55.0.10 + '@expo/config': 55.0.21(typescript@6.0.3) + '@expo/config-plugins': 55.0.11 '@expo/devcert': 1.2.1 - '@expo/env': 2.1.2 - '@expo/image-utils': 0.8.14(typescript@6.0.3) + '@expo/env': 2.1.3 + '@expo/image-utils': 0.8.17(typescript@6.0.3) '@expo/json-file': 10.2.0 - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro': 55.1.1 - '@expo/metro-config': 55.0.24(expo@55.0.27)(typescript@6.0.3) + '@expo/log-box': 55.0.13(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/metro': 55.1.2 + '@expo/metro-config': 55.0.27(expo@55.0.30)(typescript@6.0.3) '@expo/osascript': 2.7.0 '@expo/package-manager': 1.13.0 '@expo/plist': 0.5.4 - '@expo/prebuild-config': 55.0.19(expo@55.0.27)(typescript@6.0.3) - '@expo/require-utils': 55.0.5(typescript@6.0.3) - '@expo/router-server': 55.0.18(@expo/metro-runtime@55.0.10)(expo-constants@55.0.16)(expo-font@55.0.8)(expo-router@55.0.14)(expo-server@55.0.11)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@expo/schema-utils': 55.0.4 - '@expo/spawn-async': 1.7.2 + '@expo/prebuild-config': 55.0.22(expo@55.0.30)(typescript@6.0.3) + '@expo/require-utils': 55.0.8(typescript@6.0.3) + '@expo/router-server': 55.0.19(@expo/metro-runtime@55.0.10)(expo-constants@55.0.17)(expo-font@55.0.8)(expo-router@55.0.18)(expo-server@55.0.12)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@expo/schema-utils': 55.0.5 + '@expo/spawn-async': 1.8.0 '@expo/ws-tunnel': 1.0.6 '@expo/xcpretty': 4.4.4 - '@react-native/dev-middleware': 0.83.6 + '@react-native/dev-middleware': 0.83.10 accepts: 1.3.8 + agent-cli-detector: 0.1.7 arg: 5.0.2 better-opn: 3.0.2 bplist-creator: 0.1.0 @@ -8650,13 +8746,13 @@ snapshots: connect: 3.7.0 debug: 4.4.3 dnssd-advertise: 1.1.6 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-server: 55.0.11 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-server: 55.0.12 fetch-nodeshim: 0.4.10 getenv: 2.0.0 glob: 13.0.6 lan-network: 0.2.1 - multitars: 1.0.0 + multitars: 1.0.2 node-forge: 1.4.0 npm-package-arg: 11.0.3 ora: 3.4.0 @@ -8665,7 +8761,7 @@ snapshots: progress: 2.0.3 prompts: 2.4.2 resolve-from: 5.0.0 - semver: 7.8.4 + semver: 7.8.5 send: 0.19.2 slugify: 1.6.9 source-map-support: 0.5.21 @@ -8674,11 +8770,11 @@ snapshots: terminal-link: 2.1.1 toqr: 0.1.1 wrap-ansi: 7.0.0 - ws: 8.21.0 + ws: 8.21.3 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.14(50649306d987d6f4e510b7a8e94ea6ba) - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo-router: 55.0.18(2f99795f9796def5cdb1516a493dc117) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - '@expo/dom-webview' - '@expo/metro-runtime' @@ -8696,9 +8792,9 @@ snapshots: dependencies: node-forge: 1.4.0 - '@expo/config-plugins@55.0.10': + '@expo/config-plugins@55.0.11': dependencies: - '@expo/config-types': 55.0.5 + '@expo/config-types': 55.0.6 '@expo/json-file': 10.0.16 '@expo/plist': 0.5.4 '@expo/sdk-runtime-versions': 1.0.0 @@ -8707,7 +8803,7 @@ snapshots: getenv: 2.0.0 glob: 13.0.6 resolve-from: 5.0.0 - semver: 7.8.4 + semver: 7.8.5 slugify: 1.6.9 xcode: 3.0.1 xml2js: 0.6.0 @@ -8725,7 +8821,7 @@ snapshots: getenv: 2.0.0 glob: 13.0.6 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.5 slugify: 1.6.9 xcode: 3.0.1 xml2js: 0.6.0 @@ -8734,6 +8830,8 @@ snapshots: '@expo/config-types@55.0.5': {} + '@expo/config-types@55.0.6': {} + '@expo/config@55.0.16(typescript@5.9.3)': dependencies: '@expo/config-plugins': 55.0.8 @@ -8744,39 +8842,23 @@ snapshots: getenv: 2.0.0 glob: 13.0.6 resolve-workspace-root: 2.0.1 - semver: 7.7.4 + semver: 7.8.5 slugify: 1.6.9 transitivePeerDependencies: - supports-color - typescript - '@expo/config@55.0.16(typescript@6.0.3)': + '@expo/config@55.0.21(typescript@6.0.3)': dependencies: - '@expo/config-plugins': 55.0.8 - '@expo/config-types': 55.0.5 - '@expo/json-file': 10.0.14 - '@expo/require-utils': 55.0.5(typescript@6.0.3) - deepmerge: 4.3.1 - getenv: 2.0.0 - glob: 13.0.6 - resolve-workspace-root: 2.0.1 - semver: 7.7.4 - slugify: 1.6.9 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/config@55.0.18(typescript@6.0.3)': - dependencies: - '@expo/config-plugins': 55.0.10 - '@expo/config-types': 55.0.5 + '@expo/config-plugins': 55.0.11 + '@expo/config-types': 55.0.6 '@expo/json-file': 10.2.0 - '@expo/require-utils': 55.0.5(typescript@6.0.3) + '@expo/require-utils': 55.0.8(typescript@6.0.3) deepmerge: 4.3.1 getenv: 2.0.0 glob: 13.0.6 resolve-workspace-root: 2.0.1 - semver: 7.8.4 + semver: 7.8.5 slugify: 1.6.9 transitivePeerDependencies: - supports-color @@ -8789,20 +8871,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/devtools@55.0.3(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/devtools@55.0.3(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: chalk: 4.1.2 optionalDependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - '@expo/dom-webview@55.0.5(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/dom-webview@55.0.5(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - '@expo/env@2.1.2': + '@expo/env@2.1.3': dependencies: chalk: 4.1.2 debug: 4.4.3 @@ -8810,10 +8892,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/fingerprint@0.16.7': + '@expo/env@2.4.2': dependencies: - '@expo/env': 2.1.2 - '@expo/spawn-async': 1.7.2 + chalk: 4.1.2 + debug: 4.4.3 + getenv: 2.0.0 + transitivePeerDependencies: + - supports-color + + '@expo/fingerprint@0.16.8': + dependencies: + '@expo/env': 2.4.2 + '@expo/spawn-async': 1.8.0 arg: 5.0.2 chalk: 4.1.2 debug: 4.4.3 @@ -8822,19 +8912,19 @@ snapshots: ignore: 5.3.2 minimatch: 10.2.5 resolve-from: 5.0.0 - semver: 7.8.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color - '@expo/image-utils@0.8.14(typescript@6.0.3)': + '@expo/image-utils@0.8.17(typescript@6.0.3)': dependencies: - '@expo/require-utils': 55.0.5(typescript@6.0.3) - '@expo/spawn-async': 1.7.2 + '@expo/require-utils': 55.0.8(typescript@6.0.3) + '@expo/spawn-async': 1.8.0 chalk: 4.1.2 getenv: 2.0.0 jimp-compact: 0.16.1 parse-png: 2.1.0 - semver: 7.7.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color - typescript @@ -8859,42 +8949,42 @@ snapshots: '@babel/code-frame': 7.29.7 json5: 2.2.3 - '@expo/local-build-cache-provider@55.0.14(typescript@6.0.3)': + '@expo/local-build-cache-provider@55.0.16(typescript@6.0.3)': dependencies: - '@expo/config': 55.0.18(typescript@6.0.3) + '@expo/config': 55.0.21(typescript@6.0.3) chalk: 4.1.2 transitivePeerDependencies: - supports-color - typescript - '@expo/log-box@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/log-box@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/dom-webview': 55.0.5(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) anser: 1.4.10 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) stacktrace-parser: 0.1.11 - '@expo/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/log-box@55.0.13(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/dom-webview': 55.0.5(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) anser: 1.4.10 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) stacktrace-parser: 0.1.11 - '@expo/metro-config@55.0.24(expo@55.0.27)(typescript@6.0.3)': + '@expo/metro-config@55.0.27(expo@55.0.30)(typescript@6.0.3)': dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@expo/config': 55.0.18(typescript@6.0.3) - '@expo/env': 2.1.2 + '@babel/generator': 7.29.8 + '@expo/config': 55.0.21(typescript@6.0.3) + '@expo/env': 2.1.3 '@expo/json-file': 10.0.16 - '@expo/metro': 55.1.1 - '@expo/spawn-async': 1.7.2 + '@expo/metro': 55.1.2 + '@expo/spawn-async': 1.8.0 browserslist: 4.28.2 chalk: 4.1.2 debug: 4.4.3 @@ -8907,44 +8997,44 @@ snapshots: postcss: 8.5.25 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-runtime@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/metro-runtime@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - '@expo/log-box': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/log-box': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) anser: 1.4.10 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) pretty-format: 29.7.0 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) stacktrace-parser: 0.1.11 whatwg-fetch: 3.6.20 optionalDependencies: - react-dom: 19.2.6(react@19.2.6) + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@expo/dom-webview' - '@expo/metro@55.1.1': + '@expo/metro@55.1.2': dependencies: - metro: 0.83.7 - metro-babel-transformer: 0.83.7 - metro-cache: 0.83.7 - metro-cache-key: 0.83.7 - metro-config: 0.83.7 - metro-core: 0.83.7 - metro-file-map: 0.83.7 - metro-minify-terser: 0.83.7 - metro-resolver: 0.83.7 - metro-runtime: 0.83.7 - metro-source-map: 0.83.7 - metro-symbolicate: 0.83.7 - metro-transform-plugins: 0.83.7 - metro-transform-worker: 0.83.7 + metro: 0.83.8 + metro-babel-transformer: 0.83.8 + metro-cache: 0.83.8 + metro-cache-key: 0.83.8 + metro-config: 0.83.8 + metro-core: 0.83.8 + metro-file-map: 0.83.8 + metro-minify-terser: 0.83.8 + metro-resolver: 0.83.8 + metro-runtime: 0.83.8 + metro-source-map: 0.83.8 + metro-symbolicate: 0.83.8 + metro-transform-plugins: 0.83.8 + metro-transform-worker: 0.83.8 transitivePeerDependencies: - bufferutil - supports-color @@ -8979,35 +9069,18 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@55.0.17(expo@55.0.27)(typescript@6.0.3)': + '@expo/prebuild-config@55.0.22(expo@55.0.30)(typescript@6.0.3)': dependencies: - '@expo/config': 55.0.16(typescript@6.0.3) - '@expo/config-plugins': 55.0.8 - '@expo/config-types': 55.0.5 - '@expo/image-utils': 0.8.14(typescript@6.0.3) - '@expo/json-file': 10.0.14 - '@react-native/normalize-colors': 0.83.6 - debug: 4.4.3 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - resolve-from: 5.0.0 - semver: 7.7.4 - xml2js: 0.6.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/prebuild-config@55.0.19(expo@55.0.27)(typescript@6.0.3)': - dependencies: - '@expo/config': 55.0.18(typescript@6.0.3) - '@expo/config-plugins': 55.0.10 - '@expo/config-types': 55.0.5 - '@expo/image-utils': 0.8.14(typescript@6.0.3) + '@expo/config': 55.0.21(typescript@6.0.3) + '@expo/config-plugins': 55.0.11 + '@expo/config-types': 55.0.6 + '@expo/image-utils': 0.8.17(typescript@6.0.3) '@expo/json-file': 10.2.0 - '@react-native/normalize-colors': 0.83.6 + '@react-native/normalize-colors': 0.83.10 debug: 4.4.3 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) resolve-from: 5.0.0 - semver: 7.8.4 + semver: 7.8.5 xml2js: 0.6.0 transitivePeerDependencies: - supports-color @@ -9023,32 +9096,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/require-utils@55.0.5(typescript@6.0.3)': + '@expo/require-utils@55.0.8(typescript@6.0.3)': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.18(@expo/metro-runtime@55.0.10)(expo-constants@55.0.16)(expo-font@55.0.8)(expo-router@55.0.14)(expo-server@55.0.11)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@expo/router-server@55.0.19(@expo/metro-runtime@55.0.10)(expo-constants@55.0.17)(expo-font@55.0.8)(expo-router@55.0.18)(expo-server@55.0.12)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: debug: 4.4.3 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-font: 55.0.8(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-server: 55.0.11 - react: 19.2.6 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-font: 55.0.8(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-server: 55.0.12 + react: 19.2.8 optionalDependencies: - '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-router: 55.0.14(50649306d987d6f4e510b7a8e94ea6ba) - react-dom: 19.2.6(react@19.2.6) + '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-router: 55.0.18(2f99795f9796def5cdb1516a493dc117) + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - supports-color - '@expo/schema-utils@55.0.4': {} + '@expo/schema-utils@55.0.5': {} '@expo/sdk-runtime-versions@1.0.0': {} @@ -9062,11 +9135,11 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/vector-icons@15.1.1(expo-font@55.0.8)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/vector-icons@15.1.1(expo-font@55.0.8)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - expo-font: 55.0.8(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo-font: 55.0.8(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) '@expo/ws-tunnel@1.0.6': {} @@ -9310,7 +9383,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@mermaid-js/parser@1.2.0': + '@mermaid-js/parser@1.2.1': dependencies: '@chevrotain/types': 11.1.2 @@ -9326,328 +9399,336 @@ snapshots: '@noble/hashes@1.8.0': {} - '@orca/expo-two-way-audio@file:packages/expo-two-way-audio(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@orca/expo-two-way-audio@file:packages/expo-two-way-audio(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) '@oxc-project/types@0.137.0': {} - '@oxfmt/binding-android-arm-eabi@0.52.0': + '@oxfmt/binding-android-arm-eabi@0.65.0': optional: true - '@oxfmt/binding-android-arm64@0.52.0': + '@oxfmt/binding-android-arm64@0.65.0': optional: true - '@oxfmt/binding-darwin-arm64@0.52.0': + '@oxfmt/binding-darwin-arm64@0.65.0': optional: true - '@oxfmt/binding-darwin-x64@0.52.0': + '@oxfmt/binding-darwin-x64@0.65.0': optional: true - '@oxfmt/binding-freebsd-x64@0.52.0': + '@oxfmt/binding-freebsd-x64@0.65.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.52.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.65.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.52.0': + '@oxfmt/binding-linux-arm-musleabihf@0.65.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.52.0': + '@oxfmt/binding-linux-arm64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.52.0': + '@oxfmt/binding-linux-arm64-musl@0.65.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.52.0': + '@oxfmt/binding-linux-ppc64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.52.0': + '@oxfmt/binding-linux-riscv64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.52.0': + '@oxfmt/binding-linux-riscv64-musl@0.65.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.52.0': + '@oxfmt/binding-linux-s390x-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.52.0': + '@oxfmt/binding-linux-x64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.52.0': + '@oxfmt/binding-linux-x64-musl@0.65.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.52.0': + '@oxfmt/binding-openharmony-arm64@0.65.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.52.0': + '@oxfmt/binding-win32-arm64-msvc@0.65.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.52.0': + '@oxfmt/binding-win32-ia32-msvc@0.65.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.52.0': + '@oxfmt/binding-win32-x64-msvc@0.65.0': optional: true - '@oxlint/binding-android-arm-eabi@1.71.0': + '@oxlint/binding-android-arm-eabi@1.80.0': optional: true - '@oxlint/binding-android-arm64@1.71.0': + '@oxlint/binding-android-arm64@1.80.0': optional: true - '@oxlint/binding-darwin-arm64@1.71.0': + '@oxlint/binding-darwin-arm64@1.80.0': optional: true - '@oxlint/binding-darwin-x64@1.71.0': + '@oxlint/binding-darwin-x64@1.80.0': optional: true - '@oxlint/binding-freebsd-x64@1.71.0': + '@oxlint/binding-freebsd-x64@1.80.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.71.0': + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.71.0': + '@oxlint/binding-linux-arm-musleabihf@1.80.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.71.0': + '@oxlint/binding-linux-arm64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.71.0': + '@oxlint/binding-linux-arm64-musl@1.80.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.71.0': + '@oxlint/binding-linux-ppc64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.71.0': + '@oxlint/binding-linux-riscv64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.71.0': + '@oxlint/binding-linux-riscv64-musl@1.80.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.71.0': + '@oxlint/binding-linux-s390x-gnu@1.80.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.71.0': + '@oxlint/binding-linux-x64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-x64-musl@1.71.0': + '@oxlint/binding-linux-x64-musl@1.80.0': optional: true - '@oxlint/binding-openharmony-arm64@1.71.0': + '@oxlint/binding-openharmony-arm64@1.80.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.71.0': + '@oxlint/binding-win32-arm64-msvc@1.80.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.71.0': + '@oxlint/binding-win32-ia32-msvc@1.80.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.71.0': + '@oxlint/binding-win32-x64-msvc@1.80.0': optional: true '@pkgr/core@0.2.9': {} '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-collection@1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-collection@1.1.7(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dialog@1.1.15(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dialog@1.1.15(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-focus-scope@1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-focus-scope@1.1.7(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-portal@1.1.9(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-portal@1.1.9(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-presence@1.1.5(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-presence@1.1.5(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-roving-focus@1.1.11(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-roving-focus@1.1.11(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-tabs@1.1.13(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-tabs@1.1.13(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.6)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.6 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@react-native-async-storage/async-storage@2.2.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))': + '@react-native-async-storage/async-storage@2.2.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))': dependencies: merge-options: 3.0.4 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - '@react-native/assets-registry@0.83.9': {} + '@react-native/assets-registry@0.83.10': {} + + '@react-native/babel-plugin-codegen@0.83.10(@babel/core@7.29.7)': + dependencies: + '@babel/traverse': 7.29.8 + '@react-native/codegen': 0.83.10(@babel/core@7.29.7) + transitivePeerDependencies: + - '@babel/core' + - supports-color '@react-native/babel-plugin-codegen@0.83.6(@babel/core@7.29.7)': dependencies: @@ -9665,6 +9746,56 @@ snapshots: - '@babel/core' - supports-color + '@react-native/babel-preset@0.83.10(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-export-default-from': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-transform-arrow-functions': 7.27.1(@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-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-classes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-flow-strip-types': 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.27.1(@babel/core@7.29.7) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 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-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@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.27.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-react-display-name': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regenerator': 7.29.8(@babel/core@7.29.7) + '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) + '@babel/template': 7.29.7 + '@react-native/babel-plugin-codegen': 0.83.10(@babel/core@7.29.7) + babel-plugin-syntax-hermes-parser: 0.32.0 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.7) + react-refresh: 0.14.2 + transitivePeerDependencies: + - supports-color + '@react-native/babel-preset@0.83.6(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 @@ -9753,20 +9884,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/codegen@0.83.6(@babel/core@7.29.7)': + '@react-native/codegen@0.83.10(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 glob: 7.2.3 hermes-parser: 0.32.0 invariant: 2.2.4 nullthrows: 1.1.1 - yargs: 17.7.2 + yargs: 17.7.3 - '@react-native/codegen@0.83.9(@babel/core@7.29.7)': + '@react-native/codegen@0.83.6(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.3 + '@babel/parser': 7.29.7 glob: 7.2.3 hermes-parser: 0.32.0 invariant: 2.2.4 @@ -9783,15 +9914,15 @@ snapshots: tinyglobby: 0.2.17 yargs: 17.7.3 - '@react-native/community-cli-plugin@0.83.9(@react-native/metro-config@0.85.2(@babel/core@7.29.7))': + '@react-native/community-cli-plugin@0.83.10(@react-native/metro-config@0.85.2(@babel/core@7.29.7))': dependencies: - '@react-native/dev-middleware': 0.83.9 + '@react-native/dev-middleware': 0.83.10 debug: 4.4.3 invariant: 2.2.4 metro: 0.83.7 metro-config: 0.83.7 metro-core: 0.83.7 - semver: 7.7.4 + semver: 7.8.5 optionalDependencies: '@react-native/metro-config': 0.85.2(@babel/core@7.29.7) transitivePeerDependencies: @@ -9799,25 +9930,18 @@ snapshots: - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.83.6': {} + '@react-native/debugger-frontend@0.83.10': {} - '@react-native/debugger-frontend@0.83.9': {} - - '@react-native/debugger-shell@0.83.6': + '@react-native/debugger-shell@0.83.10': dependencies: cross-spawn: 7.0.6 fb-dotslash: 0.5.8 - '@react-native/debugger-shell@0.83.9': - dependencies: - cross-spawn: 7.0.6 - fb-dotslash: 0.5.8 - - '@react-native/dev-middleware@0.83.6': + '@react-native/dev-middleware@0.83.10': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.83.6 - '@react-native/debugger-shell': 0.83.6 + '@react-native/debugger-frontend': 0.83.10 + '@react-native/debugger-shell': 0.83.10 chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 @@ -9826,34 +9950,15 @@ snapshots: nullthrows: 1.1.1 open: 7.4.2 serve-static: 1.16.3 - ws: 7.5.11 + ws: 7.5.13 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@react-native/dev-middleware@0.83.9': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.83.9 - '@react-native/debugger-shell': 0.83.9 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 4.4.3 - invariant: 2.2.4 - nullthrows: 1.1.1 - open: 7.4.2 - serve-static: 1.16.3 - ws: 7.5.11 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + '@react-native/gradle-plugin@0.83.10': {} - '@react-native/gradle-plugin@0.83.9': {} - - '@react-native/js-polyfills@0.83.9': {} + '@react-native/js-polyfills@0.83.10': {} '@react-native/js-polyfills@0.85.2': {} @@ -9880,77 +9985,75 @@ snapshots: '@react-native/normalize-colors@0.74.89': {} - '@react-native/normalize-colors@0.83.6': {} + '@react-native/normalize-colors@0.83.10': {} - '@react-native/normalize-colors@0.83.9': {} - - '@react-native/virtualized-lists@0.83.9(@types/react@19.2.14)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@react-native/virtualized-lists@0.83.10(@types/react@19.2.14)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@react-navigation/bottom-tabs@7.15.11(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-screens@4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': - dependencies: - '@react-navigation/elements': 2.9.15(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@react-navigation/native': 7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + ? '@react-navigation/bottom-tabs@7.15.11(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-screens@4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)' + : dependencies: + '@react-navigation/elements': 2.9.15(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@react-navigation/native': 7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) color: 4.2.3 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-safe-area-context: 5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-screens: 4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-safe-area-context: 5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-screens: 4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/core@7.17.2(react@19.2.6)': + '@react-navigation/core@7.17.2(react@19.2.8)': dependencies: '@react-navigation/routers': 7.5.3 escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.18 query-string: 7.1.3 - react: 19.2.6 + react: 19.2.8 react-is: 19.2.6 - use-latest-callback: 0.2.6(react@19.2.6) - use-sync-external-store: 1.6.0(react@19.2.6) + use-latest-callback: 0.2.6(react@19.2.8) + use-sync-external-store: 1.6.0(react@19.2.8) - '@react-navigation/elements@2.9.15(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@react-navigation/elements@2.9.15(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - '@react-navigation/native': 7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@react-navigation/native': 7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) color: 4.2.3 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-safe-area-context: 5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - use-latest-callback: 0.2.6(react@19.2.6) - use-sync-external-store: 1.6.0(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-safe-area-context: 5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + use-latest-callback: 0.2.6(react@19.2.8) + use-sync-external-store: 1.6.0(react@19.2.8) - '@react-navigation/native-stack@7.14.12(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-screens@4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': - dependencies: - '@react-navigation/elements': 2.9.15(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@react-navigation/native': 7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + ? '@react-navigation/native-stack@7.14.12(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-screens@4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)' + : dependencies: + '@react-navigation/elements': 2.9.15(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@react-navigation/native': 7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) color: 4.2.3 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-safe-area-context: 5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-screens: 4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-safe-area-context: 5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-screens: 4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)': dependencies: - '@react-navigation/core': 7.17.2(react@19.2.6) + '@react-navigation/core': 7.17.2(react@19.2.8) escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.18 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - use-latest-callback: 0.2.6(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + use-latest-callback: 0.2.6(react@19.2.8) '@react-navigation/routers@7.5.3': dependencies: @@ -10023,14 +10126,14 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react-test-renderer@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: jest-matcher-utils: 30.3.0 picocolors: 1.1.1 pretty-format: 30.3.0 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-test-renderer: 19.2.6(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-test-renderer: 19.2.8(react@19.2.8) redent: 3.0.0 optionalDependencies: jest: 29.7.0(@types/node@26.1.2) @@ -10242,9 +10345,9 @@ snapshots: dependencies: undici-types: 8.3.0 - '@types/react-native@0.73.0(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)': + '@types/react-native@0.73.0(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)': dependencies: - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - '@babel/core' - '@react-native-community/cli' @@ -10284,7 +10387,7 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@6.0.3) @@ -10304,7 +10407,7 @@ snapshots: dependencies: '@typescript-eslint/scope-manager': 8.59.2 '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3 eslint: 9.39.4 @@ -10321,15 +10424,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.2(typescript@6.0.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@6.0.3) - '@typescript-eslint/types': 8.59.2 - debug: 4.4.3 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/scope-manager@8.59.2': dependencies: '@typescript-eslint/types': 8.59.2 @@ -10339,10 +10433,6 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.59.2(typescript@6.0.3)': - dependencies: - typescript: 6.0.3 - '@typescript-eslint/type-utils@8.59.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.59.2 @@ -10365,28 +10455,13 @@ snapshots: '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.59.2(typescript@6.0.3)': - dependencies: - '@typescript-eslint/project-service': 8.59.2(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@6.0.3) - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/visitor-keys': 8.59.2 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.7.4 - tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/utils@8.59.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) @@ -10403,6 +10478,37 @@ snapshots: '@typescript-eslint/types': 8.59.2 eslint-visitor-keys: 5.0.1 + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-linux-arm@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-linux-x64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260707.2': + optional: true + + '@typescript/native-preview@7.0.0-dev.20260707.2': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260707.2 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260707.2 + '@ungap/structured-clone@1.3.1': {} '@upsetjs/venn.js@2.0.0': @@ -10410,44 +10516,44 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - '@vitest/expect@4.1.9': + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.9(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.9 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0) - '@vitest/pretty-format@4.1.9': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.9': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.9': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.9': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.9': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.9 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -10504,6 +10610,8 @@ snapshots: agent-base@7.1.4: {} + agent-cli-detector@0.1.7: {} + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -10740,7 +10848,7 @@ snapshots: '@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-expo@55.0.21(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.27)(react-refresh@0.14.2): + babel-preset-expo@55.0.21(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.30)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.28.6 @@ -10768,14 +10876,14 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) transitivePeerDependencies: - '@babel/core' - supports-color - babel-preset-expo@55.0.23(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.27)(react-refresh@0.14.2): + babel-preset-expo@55.0.25(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.30)(react-refresh@0.14.2): dependencies: - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-module-imports': 7.29.7 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.7) '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7) @@ -10791,7 +10899,7 @@ snapshots: '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) '@babel/preset-react': 7.28.5(@babel/core@7.29.7) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) - '@react-native/babel-preset': 0.83.6(@babel/core@7.29.7) + '@react-native/babel-preset': 0.83.10(@babel/core@7.29.7) babel-plugin-react-compiler: 1.0.0 babel-plugin-react-native-web: 0.21.2 babel-plugin-syntax-hermes-parser: 0.32.1 @@ -10801,7 +10909,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -10884,7 +10992,7 @@ snapshots: buffer-image-size@0.6.4: dependencies: - '@types/node': 26.1.1 + '@types/node': 26.1.2 buffer@6.0.3: dependencies: @@ -10955,7 +11063,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 26.1.1 + '@types/node': 26.1.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -10964,7 +11072,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 26.1.1 + '@types/node': 26.1.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -11658,7 +11766,7 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.39.4): dependencies: eslint: 9.39.4 - semver: 7.7.4 + semver: 7.8.5 eslint-config-prettier@9.1.2(eslint@9.39.4): dependencies: @@ -11666,11 +11774,11 @@ snapshots: eslint-config-universe@15.0.4(eslint@9.39.4)(prettier@2.8.8)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@6.0.3) eslint: 9.39.4 eslint-config-prettier: 9.1.2(eslint@9.39.4) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint@9.39.4) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) eslint-plugin-n: 17.24.0(eslint@9.39.4)(typescript@5.9.3) eslint-plugin-node: 11.1.0(eslint@9.39.4) eslint-plugin-prettier: 5.5.5(eslint-config-prettier@9.1.2(eslint@9.39.4))(eslint@9.39.4)(prettier@2.8.8) @@ -11694,7 +11802,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4): dependencies: debug: 3.2.7 optionalDependencies: @@ -11717,7 +11825,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint@9.39.4): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -11728,7 +11836,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4) hasown: 2.0.3 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -11756,7 +11864,7 @@ snapshots: globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.7.4 + semver: 7.8.5 ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript @@ -11914,159 +12022,154 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - expo-application@55.0.14(expo@55.0.27): + expo-application@55.0.19(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-asset@55.0.17(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3): + expo-asset@55.0.20(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3): dependencies: - '@expo/image-utils': 0.8.14(typescript@6.0.3) - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + '@expo/image-utils': 0.8.17(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - supports-color - typescript - expo-build-properties@55.0.13(expo@55.0.27): + expo-build-properties@55.0.18(expo@55.0.30): dependencies: - '@expo/schema-utils': 55.0.4 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + '@expo/schema-utils': 55.0.5 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.5 - expo-camera@55.0.18(@types/emscripten@1.41.5)(expo@55.0.27)(react-native-web@0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-camera@55.0.23(@types/emscripten@1.41.5)(expo@55.0.30)(react-native-web@0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: barcode-detector: 3.1.3(@types/emscripten@1.41.5) - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) optionalDependencies: - react-native-web: 0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-native-web: 0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) transitivePeerDependencies: - '@types/emscripten' - expo-clipboard@55.0.13(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-clipboard@55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - expo-constants@55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)): + expo-constants@55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)): dependencies: - '@expo/env': 2.1.2 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + '@expo/env': 2.1.3 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - supports-color - expo-crypto@55.0.14(expo@55.0.27): + expo-crypto@55.0.19(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-dev-client@55.0.35(expo@55.0.27): + expo-dev-client@55.0.39(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-dev-launcher: 55.0.36(expo@55.0.27) - expo-dev-menu: 55.0.30(expo@55.0.27) - expo-dev-menu-interface: 55.0.2(expo@55.0.27) - expo-manifests: 55.0.17(expo@55.0.27) - expo-updates-interface: 55.1.6(expo@55.0.27) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-dev-launcher: 55.0.40(expo@55.0.30) + expo-dev-menu: 55.0.34(expo@55.0.30) + expo-dev-menu-interface: 55.0.2(expo@55.0.30) + expo-manifests: 55.0.21(expo@55.0.30) + expo-updates-interface: 55.1.6(expo@55.0.30) - expo-dev-launcher@55.0.36(expo@55.0.27): + expo-dev-launcher@55.0.40(expo@55.0.30): dependencies: - '@expo/schema-utils': 55.0.4 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-dev-menu: 55.0.30(expo@55.0.27) - expo-manifests: 55.0.17(expo@55.0.27) + '@expo/schema-utils': 55.0.5 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-dev-menu: 55.0.34(expo@55.0.30) + expo-manifests: 55.0.21(expo@55.0.30) - expo-dev-menu-interface@55.0.2(expo@55.0.27): + expo-dev-menu-interface@55.0.2(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-dev-menu@55.0.30(expo@55.0.27): + expo-dev-menu@55.0.34(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-dev-menu-interface: 55.0.2(expo@55.0.27) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-dev-menu-interface: 55.0.2(expo@55.0.30) - expo-document-picker@55.0.13(expo@55.0.27): + expo-document-picker@55.0.17(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-file-system@55.0.19(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)): + expo-file-system@55.0.26(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - expo-file-system@55.0.23(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)): + expo-font@55.0.8(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - - expo-font@55.0.8(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): - dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) fontfaceobserver: 2.3.0 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - expo-glass-effect@55.0.11(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-glass-effect@55.0.11(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - expo-haptics@55.0.14(expo@55.0.27): + expo-haptics@55.0.18(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-image-loader@55.0.1(expo@55.0.27): + expo-image-loader@55.0.1(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-image-manipulator@55.0.17(expo@55.0.27): + expo-image-manipulator@55.0.21(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-image-loader: 55.0.1(expo@55.0.27) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-image-loader: 55.0.1(expo@55.0.30) - expo-image-picker@55.0.20(expo@55.0.27): + expo-image-picker@55.0.24(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-image-loader: 55.0.1(expo@55.0.27) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-image-loader: 55.0.1(expo@55.0.30) - expo-image@55.0.10(expo@55.0.27)(react-native-web@0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-image@55.0.11(expo@55.0.30)(react-native-web@0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) sf-symbols-typescript: 2.2.0 optionalDependencies: - react-native-web: 0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-native-web: 0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) expo-json-utils@55.0.2: {} - expo-keep-awake@55.0.8(expo@55.0.27)(react@19.2.6): + expo-keep-awake@55.0.8(expo@55.0.30)(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 - expo-linking@55.0.15(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-linking@55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) invariant: 2.2.4 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - expo - supports-color - expo-manifests@55.0.17(expo@55.0.27): + expo-manifests@55.0.21(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) expo-json-utils: 55.0.2 - expo-module-scripts@55.0.2(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.25.4)(eslint@9.39.4)(expo@55.0.27)(jest@29.7.0(@types/node@26.1.2))(prettier@2.8.8)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react-refresh@0.14.2)(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6): + expo-module-scripts@55.0.2(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.25.4)(eslint@9.39.4)(expo@55.0.30)(jest@29.7.0(@types/node@26.1.2))(prettier@2.8.8)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react-refresh@0.14.2)(react-test-renderer@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@babel/cli': 7.28.6(@babel/core@7.29.7) '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.7) @@ -12074,15 +12177,15 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) '@expo/npm-proofread': 1.0.1 '@expo/spawn-async': 1.7.2 - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react-test-renderer@19.2.8(react@19.2.8))(react@19.2.8) '@tsconfig/node18': 18.2.6 '@types/jest': 29.5.14 babel-plugin-dynamic-import-node: 2.3.3 - babel-preset-expo: 55.0.21(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.27)(react-refresh@0.14.2) + babel-preset-expo: 55.0.21(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.30)(react-refresh@0.14.2) commander: 12.1.0 eslint-config-universe: 15.0.4(eslint@9.39.4)(prettier@2.8.8)(typescript@5.9.3) glob: 13.0.6 - jest-expo: 55.0.17(@babel/core@7.29.7)(expo@55.0.27)(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + jest-expo: 55.0.17(@babel/core@7.29.7)(expo@55.0.30)(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@5.9.3) jest-snapshot-prettier: prettier@2.8.8 jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@26.1.2)) resolve-workspace-root: 2.0.1 @@ -12112,85 +12215,85 @@ snapshots: - supports-color - utf-8-validate - expo-modules-autolinking@55.0.24(typescript@6.0.3): + expo-modules-autolinking@55.0.27(typescript@6.0.3): dependencies: - '@expo/require-utils': 55.0.5(typescript@6.0.3) - '@expo/spawn-async': 1.7.2 + '@expo/require-utils': 55.0.8(typescript@6.0.3) + '@expo/spawn-async': 1.8.0 chalk: 4.1.2 commander: 7.2.0 transitivePeerDependencies: - supports-color - typescript - expo-modules-core@55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-modules-core@55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: invariant: 2.2.4 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) optionalDependencies: - react-native-worklets: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react-native-worklets: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) - expo-network@55.0.14(expo@55.0.27)(react@19.2.6): + expo-network@55.0.18(expo@55.0.30)(react@19.2.8): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - react: 19.2.6 + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + react: 19.2.8 - expo-notifications@55.0.22(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3): + expo-notifications@55.0.27(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3): dependencies: - '@expo/image-utils': 0.8.14(typescript@6.0.3) + '@expo/image-utils': 0.8.17(typescript@6.0.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-application: 55.0.14(expo@55.0.27) - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-application: 55.0.19(expo@55.0.30) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.14(50649306d987d6f4e510b7a8e94ea6ba): + expo-router@55.0.18(2f99795f9796def5cdb1516a493dc117): dependencies: - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/schema-utils': 55.0.4 - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.6) - '@radix-ui/react-tabs': 1.1.13(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@react-navigation/bottom-tabs': 7.15.11(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-screens@4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@react-navigation/native': 7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@react-navigation/native-stack': 7.14.12(@react-navigation/native@7.2.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-screens@4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/log-box': 55.0.13(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/schema-utils': 55.0.5 + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-tabs': 1.1.13(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@react-navigation/bottom-tabs': 7.15.11(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-screens@4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@react-navigation/native': 7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@react-navigation/native-stack': 7.14.12(@react-navigation/native@7.2.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native-screens@4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-glass-effect: 55.0.11(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-image: 55.0.10(expo@55.0.27)(react-native-web@0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-linking: 55.0.15(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-server: 55.0.9 - expo-symbols: 55.0.8(expo-font@55.0.8)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-glass-effect: 55.0.11(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-image: 55.0.11(expo@55.0.30)(react-native-web@0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-linking: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-server: 55.0.12 + expo-symbols: 55.0.9(expo-font@55.0.8)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) fast-deep-equal: 3.1.3 invariant: 2.2.4 nanoid: 3.3.18 query-string: 7.1.3 - react: 19.2.6 + react: 19.2.8 react-fast-compare: 3.2.2 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-is-edge-to-edge: 1.3.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-safe-area-context: 5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-screens: 4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-safe-area-context: 5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-screens: 4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) semver: 7.6.3 server-only: 0.0.1 sf-symbols-typescript: 2.2.0 shallowequal: 1.1.0 - use-latest-callback: 0.2.6(react@19.2.6) - vaul: 1.1.2(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + use-latest-callback: 0.2.6(react@19.2.8) + vaul: 1.1.2(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) - react-dom: 19.2.6(react@19.2.6) - react-native-gesture-handler: 2.31.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-reanimated: 4.3.0(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-web: 0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react-test-renderer@19.2.8(react@19.2.8))(react@19.2.8) + react-dom: 19.2.8(react@19.2.8) + react-native-gesture-handler: 2.31.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-reanimated: 4.3.4(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-web: 0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@types/react' @@ -12198,72 +12301,70 @@ snapshots: - expo-font - supports-color - expo-secure-store@55.0.13(expo@55.0.27): + expo-secure-store@55.0.18(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo-server@55.0.11: {} + expo-server@55.0.12: {} - expo-server@55.0.9: {} - - expo-splash-screen@55.0.20(expo@55.0.27)(typescript@6.0.3): + expo-splash-screen@55.0.25(expo@55.0.30)(typescript@6.0.3): dependencies: - '@expo/prebuild-config': 55.0.17(expo@55.0.27)(typescript@6.0.3) - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + '@expo/prebuild-config': 55.0.22(expo@55.0.30)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) transitivePeerDependencies: - supports-color - typescript - expo-status-bar@55.0.6(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-status-bar@55.0.6(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-is-edge-to-edge: 1.3.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) - expo-symbols@55.0.8(expo-font@55.0.8)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-symbols@55.0.9(expo-font@55.0.8)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: '@expo-google-fonts/material-symbols': 0.4.34 - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-font: 55.0.8(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) + expo-font: 55.0.8(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) sf-symbols-typescript: 2.2.0 - expo-updates-interface@55.1.6(expo@55.0.27): + expo-updates-interface@55.1.6(expo@55.0.30): dependencies: - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) - expo@55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3): + expo@55.0.30(10e8e71dd92768dd7f344108f3edbbe3): dependencies: '@babel/runtime': 7.29.7 - '@expo/cli': 55.0.33(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.16)(expo-font@55.0.8)(expo-router@55.0.14)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - '@expo/config': 55.0.18(typescript@6.0.3) - '@expo/config-plugins': 55.0.10 - '@expo/devtools': 55.0.3(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/fingerprint': 0.16.7 - '@expo/local-build-cache-provider': 55.0.14(typescript@6.0.3) - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro': 55.1.1 - '@expo/metro-config': 55.0.24(expo@55.0.27)(typescript@6.0.3) - '@expo/vector-icons': 15.1.1(expo-font@55.0.8)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/cli': 55.0.36(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.17)(expo-font@55.0.8)(expo-router@55.0.18)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3) + '@expo/config': 55.0.21(typescript@6.0.3) + '@expo/config-plugins': 55.0.11 + '@expo/devtools': 55.0.3(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/fingerprint': 0.16.8 + '@expo/local-build-cache-provider': 55.0.16(typescript@6.0.3) + '@expo/log-box': 55.0.13(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/metro': 55.1.2 + '@expo/metro-config': 55.0.27(expo@55.0.30)(typescript@6.0.3) + '@expo/vector-icons': 15.1.1(expo-font@55.0.8)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 55.0.23(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.27)(react-refresh@0.14.2) - expo-asset: 55.0.17(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) - expo-constants: 55.0.16(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-file-system: 55.0.23(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6)) - expo-font: 55.0.8(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-keep-awake: 55.0.8(expo@55.0.27)(react@19.2.6) - expo-modules-autolinking: 55.0.24(typescript@6.0.3) - expo-modules-core: 55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + babel-preset-expo: 55.0.25(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@55.0.30)(react-refresh@0.14.2) + expo-asset: 55.0.20(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@6.0.3) + expo-constants: 55.0.17(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-file-system: 55.0.26(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)) + expo-font: 55.0.8(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + expo-keep-awake: 55.0.8(expo@55.0.30)(react@19.2.8) + expo-modules-autolinking: 55.0.27(typescript@6.0.3) + expo-modules-core: 55.0.25(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) pretty-format: 29.7.0 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) react-refresh: 0.14.2 whatwg-url-minimum: 0.1.2 optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.27)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.27)(react-dom@19.2.6(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-webview: 13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/dom-webview': 55.0.5(expo@55.0.30)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.30)(react-dom@19.2.8(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-webview: 13.16.2(patch_hash=de6761dfa76a5491a23e49f1262566a8831cab26736a336fdffc5d4e7d05ff27)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -12286,6 +12387,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fastdom@1.0.12: + dependencies: + strictdom: 1.0.1 + fb-dotslash@0.5.8: {} fb-watchman@2.0.2: @@ -12474,15 +12579,15 @@ snapshots: hachure-fill@0.5.2: {} - happy-dom@20.11.1: + happy-dom@20.11.8: dependencies: - '@types/node': 26.1.1 + '@types/node': 26.1.2 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 buffer-image-size: 0.6.4 entities: 7.0.1 whatwg-mimetype: 3.0.0 - ws: 8.21.0 + ws: 8.21.3 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -12960,26 +13065,26 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 26.1.2 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.17(@babel/core@7.29.7)(expo@55.0.27)(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): + jest-expo@55.0.17(@babel/core@7.29.7)(expo@55.0.30)(jest@29.7.0(@types/node@26.1.2))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8)(typescript@5.9.3): dependencies: '@expo/config': 55.0.16(typescript@5.9.3) '@expo/json-file': 10.0.14 '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0 babel-jest: 29.7.0(@babel/core@7.29.7) - expo: 55.0.27(@babel/core@7.29.7)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + expo: 55.0.30(10e8e71dd92768dd7f344108f3edbbe3) jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@26.1.2)) json5: 2.2.3 lodash: 4.18.1 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-test-renderer: 19.2.0(react@19.2.6) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-test-renderer: 19.2.0(react@19.2.8) server-only: 0.0.1 stacktrace-js: 2.0.2 transitivePeerDependencies: @@ -13146,7 +13251,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color @@ -13256,7 +13361,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.21.0 + ws: 8.21.3 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -13411,11 +13516,11 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react-native@1.14.0(react-native-svg@15.15.4(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + lucide-react-native@1.14.0(react-native-svg@15.15.4(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-svg: 15.15.4(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-svg: 15.15.4(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) magic-string@0.30.21: dependencies: @@ -13454,11 +13559,11 @@ snapshots: merge-stream@2.0.0: {} - mermaid@11.16.1: + mermaid@11.17.2: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.4 - '@mermaid-js/parser': 1.2.0 + '@mermaid-js/parser': 1.2.1 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 cytoscape: 3.34.0 @@ -13470,6 +13575,7 @@ snapshots: dayjs: 1.11.21 dompurify: 3.4.13 es-toolkit: 1.50.0 + fastdom: 1.0.12 katex: 0.16.47 khroma: 2.1.0 marked: 16.4.2 @@ -13488,6 +13594,16 @@ snapshots: transitivePeerDependencies: - supports-color + metro-babel-transformer@0.83.8: + dependencies: + '@babel/core': 7.29.7 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.83.8 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-babel-transformer@0.84.4: dependencies: '@babel/core': 7.29.7 @@ -13502,6 +13618,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + metro-cache-key@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + metro-cache-key@0.84.4: dependencies: flow-enums-runtime: 0.0.6 @@ -13515,6 +13635,15 @@ snapshots: transitivePeerDependencies: - supports-color + metro-cache@0.83.8: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.83.8 + transitivePeerDependencies: + - supports-color + metro-cache@0.84.4: dependencies: exponential-backoff: 3.1.3 @@ -13533,7 +13662,22 @@ snapshots: metro-cache: 0.83.7 metro-core: 0.83.7 metro-runtime: 0.83.7 - yaml: 2.8.4 + yaml: 2.9.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-config@0.83.8: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.83.8 + metro-cache: 0.83.8 + metro-core: 0.83.8 + metro-runtime: 0.83.8 + yaml: 2.9.0 transitivePeerDependencies: - bufferutil - supports-color @@ -13560,6 +13704,12 @@ snapshots: lodash.throttle: 4.1.1 metro-resolver: 0.83.7 + metro-core@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.83.8 + metro-core@0.84.4: dependencies: flow-enums-runtime: 0.0.6 @@ -13580,6 +13730,20 @@ snapshots: transitivePeerDependencies: - supports-color + metro-file-map@0.83.8: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + metro-file-map@0.84.4: dependencies: debug: 4.4.3 @@ -13597,7 +13761,12 @@ snapshots: metro-minify-terser@0.83.7: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.46.2 + terser: 5.49.1 + + metro-minify-terser@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.49.1 metro-minify-terser@0.84.4: dependencies: @@ -13608,13 +13777,22 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + metro-resolver@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + metro-resolver@0.84.4: dependencies: flow-enums-runtime: 0.0.6 metro-runtime@0.83.7: dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 + flow-enums-runtime: 0.0.6 + + metro-runtime@0.83.8: + dependencies: + '@babel/runtime': 7.29.7 flow-enums-runtime: 0.0.6 metro-runtime@0.84.4: @@ -13624,8 +13802,8 @@ snapshots: metro-source-map@0.83.7: dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 invariant: 2.2.4 metro-symbolicate: 0.83.7 @@ -13636,6 +13814,20 @@ snapshots: transitivePeerDependencies: - supports-color + metro-source-map@0.83.8: + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.83.8 + nullthrows: 1.1.1 + ob1: 0.83.8 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-source-map@0.84.4: dependencies: '@babel/traverse': 7.29.8 @@ -13661,6 +13853,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-symbolicate@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.83.8 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-symbolicate@0.84.4: dependencies: flow-enums-runtime: 0.0.6 @@ -13675,9 +13878,20 @@ snapshots: metro-transform-plugins@0.83.7: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.1 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/generator': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.83.8: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 flow-enums-runtime: 0.0.6 nullthrows: 1.1.1 transitivePeerDependencies: @@ -13697,9 +13911,9 @@ snapshots: metro-transform-worker@0.83.7: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 metro: 0.83.7 metro-babel-transformer: 0.83.7 @@ -13714,6 +13928,26 @@ snapshots: - supports-color - utf-8-validate + metro-transform-worker@0.83.8: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + flow-enums-runtime: 0.0.6 + metro: 0.83.8 + metro-babel-transformer: 0.83.8 + metro-cache: 0.83.8 + metro-cache-key: 0.83.8 + metro-minify-terser: 0.83.8 + metro-source-map: 0.83.8 + metro-transform-plugins: 0.83.8 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro-transform-worker@0.84.4: dependencies: '@babel/core': 7.29.7 @@ -13736,13 +13970,13 @@ snapshots: metro@0.83.7: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 accepts: 2.0.0 ci-info: 2.0.0 connect: 3.7.0 @@ -13773,8 +14007,53 @@ snapshots: serialize-error: 2.1.0 source-map: 0.5.7 throat: 5.0.0 - ws: 7.5.11 - yargs: 17.7.2 + ws: 7.5.13 + yargs: 17.7.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.83.8: + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + accepts: 2.0.0 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.83.8 + metro-cache: 0.83.8 + metro-cache-key: 0.83.8 + metro-config: 0.83.8 + metro-core: 0.83.8 + metro-file-map: 0.83.8 + metro-resolver: 0.83.8 + metro-runtime: 0.83.8 + metro-source-map: 0.83.8 + metro-symbolicate: 0.83.8 + metro-transform-plugins: 0.83.8 + metro-transform-worker: 0.83.8 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.13 + yargs: 17.7.3 transitivePeerDependencies: - bufferutil - supports-color @@ -13869,7 +14148,7 @@ snapshots: ms@2.1.3: {} - multitars@1.0.0: {} + multitars@1.0.2: {} nanoid@3.3.18: {} @@ -13904,7 +14183,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.8.4 + semver: 7.8.5 validate-npm-package-name: 5.0.1 npm-run-path@4.0.1: @@ -13923,6 +14202,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + ob1@0.83.8: + dependencies: + flow-enums-runtime: 0.0.6 + ob1@0.84.4: dependencies: flow-enums-runtime: 0.0.6 @@ -14028,51 +14311,51 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxfmt@0.52.0: + oxfmt@0.65.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.52.0 - '@oxfmt/binding-android-arm64': 0.52.0 - '@oxfmt/binding-darwin-arm64': 0.52.0 - '@oxfmt/binding-darwin-x64': 0.52.0 - '@oxfmt/binding-freebsd-x64': 0.52.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.52.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.52.0 - '@oxfmt/binding-linux-arm64-gnu': 0.52.0 - '@oxfmt/binding-linux-arm64-musl': 0.52.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.52.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.52.0 - '@oxfmt/binding-linux-riscv64-musl': 0.52.0 - '@oxfmt/binding-linux-s390x-gnu': 0.52.0 - '@oxfmt/binding-linux-x64-gnu': 0.52.0 - '@oxfmt/binding-linux-x64-musl': 0.52.0 - '@oxfmt/binding-openharmony-arm64': 0.52.0 - '@oxfmt/binding-win32-arm64-msvc': 0.52.0 - '@oxfmt/binding-win32-ia32-msvc': 0.52.0 - '@oxfmt/binding-win32-x64-msvc': 0.52.0 + '@oxfmt/binding-android-arm-eabi': 0.65.0 + '@oxfmt/binding-android-arm64': 0.65.0 + '@oxfmt/binding-darwin-arm64': 0.65.0 + '@oxfmt/binding-darwin-x64': 0.65.0 + '@oxfmt/binding-freebsd-x64': 0.65.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.65.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.65.0 + '@oxfmt/binding-linux-arm64-gnu': 0.65.0 + '@oxfmt/binding-linux-arm64-musl': 0.65.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.65.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.65.0 + '@oxfmt/binding-linux-riscv64-musl': 0.65.0 + '@oxfmt/binding-linux-s390x-gnu': 0.65.0 + '@oxfmt/binding-linux-x64-gnu': 0.65.0 + '@oxfmt/binding-linux-x64-musl': 0.65.0 + '@oxfmt/binding-openharmony-arm64': 0.65.0 + '@oxfmt/binding-win32-arm64-msvc': 0.65.0 + '@oxfmt/binding-win32-ia32-msvc': 0.65.0 + '@oxfmt/binding-win32-x64-msvc': 0.65.0 - oxlint@1.71.0: + oxlint@1.80.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.71.0 - '@oxlint/binding-android-arm64': 1.71.0 - '@oxlint/binding-darwin-arm64': 1.71.0 - '@oxlint/binding-darwin-x64': 1.71.0 - '@oxlint/binding-freebsd-x64': 1.71.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.71.0 - '@oxlint/binding-linux-arm-musleabihf': 1.71.0 - '@oxlint/binding-linux-arm64-gnu': 1.71.0 - '@oxlint/binding-linux-arm64-musl': 1.71.0 - '@oxlint/binding-linux-ppc64-gnu': 1.71.0 - '@oxlint/binding-linux-riscv64-gnu': 1.71.0 - '@oxlint/binding-linux-riscv64-musl': 1.71.0 - '@oxlint/binding-linux-s390x-gnu': 1.71.0 - '@oxlint/binding-linux-x64-gnu': 1.71.0 - '@oxlint/binding-linux-x64-musl': 1.71.0 - '@oxlint/binding-openharmony-arm64': 1.71.0 - '@oxlint/binding-win32-arm64-msvc': 1.71.0 - '@oxlint/binding-win32-ia32-msvc': 1.71.0 - '@oxlint/binding-win32-x64-msvc': 1.71.0 + '@oxlint/binding-android-arm-eabi': 1.80.0 + '@oxlint/binding-android-arm64': 1.80.0 + '@oxlint/binding-darwin-arm64': 1.80.0 + '@oxlint/binding-darwin-x64': 1.80.0 + '@oxlint/binding-freebsd-x64': 1.80.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.80.0 + '@oxlint/binding-linux-arm-musleabihf': 1.80.0 + '@oxlint/binding-linux-arm64-gnu': 1.80.0 + '@oxlint/binding-linux-arm64-musl': 1.80.0 + '@oxlint/binding-linux-ppc64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-musl': 1.80.0 + '@oxlint/binding-linux-s390x-gnu': 1.80.0 + '@oxlint/binding-linux-x64-gnu': 1.80.0 + '@oxlint/binding-linux-x64-musl': 1.80.0 + '@oxlint/binding-openharmony-arm64': 1.80.0 + '@oxlint/binding-win32-arm64-msvc': 1.80.0 + '@oxlint/binding-win32-ia32-msvc': 1.80.0 + '@oxlint/binding-win32-x64-msvc': 1.80.0 p-limit@2.3.0: dependencies: @@ -14240,21 +14523,21 @@ snapshots: react-devtools-core@6.1.5: dependencies: shell-quote: 1.10.0 - ws: 7.5.11 + ws: 7.5.13 transitivePeerDependencies: - bufferutil - utf-8-validate - react-dom@19.2.6(react@19.2.6): + react-dom@19.2.8(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 scheduler: 0.27.0 react-fast-compare@3.2.2: {} - react-freeze@1.0.4(react@19.2.6): + react-freeze@1.0.4(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 react-is@16.13.1: {} @@ -14262,49 +14545,51 @@ snapshots: react-is@19.2.6: {} - react-native-gesture-handler@2.31.2(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-is@19.2.8: {} + + react-native-gesture-handler@2.31.2(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: '@egjs/hammerjs': 2.0.17 '@types/react-test-renderer': 19.1.0 hoist-non-react-statics: 3.3.2 invariant: 2.2.4 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - react-native-is-edge-to-edge@1.3.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-is-edge-to-edge@1.3.1(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - react-native-reanimated@4.3.0(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-reanimated@4.3.4(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) - react-native-is-edge-to-edge: 1.3.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - react-native-worklets: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - semver: 7.7.4 + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + react-native-worklets: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) + semver: 7.8.5 - react-native-safe-area-context@5.7.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-safe-area-context@5.7.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - react-native-screens@4.24.0(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-screens@4.24.0(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.6 - react-freeze: 1.0.4(react@19.2.6) - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-freeze: 1.0.4(react@19.2.8) + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) warn-once: 0.1.1 - react-native-svg@15.15.4(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-svg@15.15.4(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: css-select: 5.2.2 css-tree: 1.1.3 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) warn-once: 0.1.1 - react-native-web@0.21.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-native-web@0.21.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@babel/runtime': 7.29.2 '@react-native/normalize-colors': 0.74.89 @@ -14313,20 +14598,21 @@ snapshots: memoize-one: 6.0.0 nullthrows: 1.1.1 postcss-value-parser: 4.2.0 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) styleq: 0.1.3 transitivePeerDependencies: - encoding - react-native-webview@13.16.1(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-webview@13.16.2(patch_hash=de6761dfa76a5491a23e49f1262566a8831cab26736a336fdffc5d4e7d05ff27)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: + '@typescript/native-preview': 7.0.0-dev.20260707.2 escape-string-regexp: 4.0.0 invariant: 2.2.4 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) - react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8): dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.7) @@ -14340,22 +14626,22 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) '@react-native/metro-config': 0.85.2(@babel/core@7.29.7) convert-source-map: 2.0.0 - react: 19.2.6 - react-native: 0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8) semver: 7.7.4 transitivePeerDependencies: - supports-color - react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6): + react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native/assets-registry': 0.83.9 - '@react-native/codegen': 0.83.9(@babel/core@7.29.7) - '@react-native/community-cli-plugin': 0.83.9(@react-native/metro-config@0.85.2(@babel/core@7.29.7)) - '@react-native/gradle-plugin': 0.83.9 - '@react-native/js-polyfills': 0.83.9 - '@react-native/normalize-colors': 0.83.9 - '@react-native/virtualized-lists': 0.83.9(@types/react@19.2.14)(react-native@0.83.9(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@react-native/assets-registry': 0.83.10 + '@react-native/codegen': 0.83.10(@babel/core@7.29.7) + '@react-native/community-cli-plugin': 0.83.10(@react-native/metro-config@0.85.2(@babel/core@7.29.7)) + '@react-native/gradle-plugin': 0.83.10 + '@react-native/js-polyfills': 0.83.10 + '@react-native/normalize-colors': 0.83.10 + '@react-native/virtualized-lists': 0.83.10(@types/react@19.2.14)(react-native@0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8))(react@19.2.8) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -14374,16 +14660,16 @@ snapshots: nullthrows: 1.1.1 pretty-format: 29.7.0 promise: 8.3.0 - react: 19.2.6 + react: 19.2.8 react-devtools-core: 6.1.5 react-refresh: 0.14.2 regenerator-runtime: 0.13.11 scheduler: 0.27.0 - semver: 7.7.4 + semver: 7.8.5 stacktrace-parser: 0.1.11 whatwg-fetch: 3.6.20 - ws: 7.5.11 - yargs: 17.7.2 + ws: 7.5.13 + yargs: 17.7.3 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: @@ -14396,46 +14682,46 @@ snapshots: react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.6): + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.6 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.8) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.6): + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.6 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.6) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.6) + react: 19.2.8 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.8) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.6) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.6) + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.6): + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.8): dependencies: get-nonce: 1.0.1 - react: 19.2.6 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-test-renderer@19.2.0(react@19.2.6): + react-test-renderer@19.2.0(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 react-is: 19.2.6 scheduler: 0.27.0 - react-test-renderer@19.2.6(react@19.2.6): + react-test-renderer@19.2.8(react@19.2.8): dependencies: - react: 19.2.6 - react-is: 19.2.6 + react: 19.2.8 + react-is: 19.2.8 scheduler: 0.27.0 - react@19.2.6: {} + react@19.2.8: {} readdirp@3.6.0: dependencies: @@ -14606,8 +14892,6 @@ snapshots: semver@7.7.4: {} - semver@7.8.4: {} - semver@7.8.5: {} send@0.19.2: @@ -14795,6 +15079,8 @@ snapshots: strict-uri-encode@2.0.0: {} + strictdom@1.0.1: {} + string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -14919,13 +15205,6 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.46.2: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - terser@5.49.1: dependencies: '@jridgewell/source-map': 0.3.11 @@ -14981,10 +15260,6 @@ snapshots: dependencies: typescript: 5.9.3 - ts-api-utils@2.5.0(typescript@6.0.3): - dependencies: - typescript: 6.0.3 - ts-declaration-location@1.0.7(typescript@5.9.3): dependencies: picomatch: 4.0.4 @@ -15121,28 +15396,28 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.6): + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-latest-callback@0.2.6(react@19.2.6): + use-latest-callback@0.2.6(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.6): + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.8): dependencies: detect-node-es: 1.1.0 - react: 19.2.6 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-sync-external-store@1.6.0(react@19.2.6): + use-sync-external-store@1.6.0(react@19.2.8): dependencies: - react: 19.2.6 + react: 19.2.8 utils-merge@1.0.1: {} @@ -15158,11 +15433,11 @@ snapshots: vary@1.1.2: {} - vaul@1.1.2(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + vaul@1.1.2(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -15182,15 +15457,15 @@ snapshots: tsx: 4.22.4 yaml: 2.9.0 - vitest@4.1.9(@types/node@26.1.2)(happy-dom@20.11.1)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.1.2)(happy-dom@20.11.8)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.9 - '@vitest/runner': 4.1.9 - '@vitest/snapshot': 4.1.9 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.1.0(@types/node@26.1.2)(esbuild@0.25.4)(terser@5.49.1)(tsx@4.22.4)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -15206,7 +15481,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.1.2 - happy-dom: 20.11.1 + happy-dom: 20.11.8 jsdom: 20.0.3 transitivePeerDependencies: - msw @@ -15316,11 +15591,9 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@7.5.11: {} - ws@7.5.13: {} - ws@8.21.0: {} + ws@8.21.3: {} xcode@3.0.1: dependencies: @@ -15344,8 +15617,6 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.4: {} - yaml@2.9.0: {} yargs-parser@21.1.1: {} @@ -15376,11 +15647,11 @@ snapshots: zod@4.4.3: {} - zustand@5.0.13(@types/react@19.2.14)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)): + zustand@5.0.13(@types/react@19.2.14)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8)): optionalDependencies: '@types/react': 19.2.14 - react: 19.2.6 - use-sync-external-store: 1.6.0(react@19.2.6) + react: 19.2.8 + use-sync-external-store: 1.6.0(react@19.2.8) zxing-wasm@3.0.3(@types/emscripten@1.41.5): dependencies: diff --git a/mobile/pnpm-workspace.yaml b/mobile/pnpm-workspace.yaml index 35f983a345a..8f29993b7b4 100644 --- a/mobile/pnpm-workspace.yaml +++ b/mobile/pnpm-workspace.yaml @@ -1,5 +1,11 @@ allowBuilds: esbuild: true +minimumReleaseAge: 4320 + overrides: xcode>uuid: 11.1.1 + +patchedDependencies: + react-native-webview@13.16.2: patches/react-native-webview@13.16.2.patch + react-native@0.83.10: patches/react-native@0.83.10.patch diff --git a/mobile/src/browser/MobileBrowserPane.tsx b/mobile/src/browser/MobileBrowserPane.tsx index f823f309630..2922d2005a4 100644 --- a/mobile/src/browser/MobileBrowserPane.tsx +++ b/mobile/src/browser/MobileBrowserPane.tsx @@ -1,77 +1,31 @@ /* oxlint-disable react-doctor/no-adjust-state-on-prop-change -- Why: mobile browser state mirrors a remote desktop screencast session and CDP dialogs, which are external systems that cannot be derived during render. */ -import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' -import { - ActivityIndicator, - AppState, - Image, - PanResponder, - PixelRatio, - Pressable, - Text, - TextInput, - View, - type GestureResponderEvent, - type PanResponderGestureState -} from 'react-native' -import { ArrowUp, ChevronLeft, ChevronRight, RefreshCw } from 'lucide-react-native' +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' +import { AppState, type Image, type View } from 'react-native' import type { RpcClient } from '../transport/rpc-client' -import type { RpcFailure, RpcSuccess } from '../transport/types' import type { BrowserScreencastFrame, BrowserScreencastFrameMetadata } from '../transport/browser-screencast-protocol' -import { colors } from '../theme/mobile-theme' -import { - MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS, - buildMobileBrowserScreencastRequest, - type MobileBrowserViewMode -} from './browser-screencast-request' -import { - MobileBrowserPointerModifiers, - type BrowserPointerModifier -} from './MobileBrowserPointerModifiers' -import { MobileBrowserKeyRow } from './MobileBrowserKeyRow' -import { MobileBrowserToolbarIconButton } from './MobileBrowserToolbarIconButton' -import { MobileBrowserViewModeSwitch } from './MobileBrowserViewModeSwitch' +import type { MobileBrowserViewMode } from './browser-screencast-request' +import type { BrowserPointerModifier } from './MobileBrowserPointerModifiers' import { getInitialMobileBrowserViewMode, saveMobileBrowserViewMode } from './mobile-browser-view-mode-state' +import type { BrowserTouchLayout, BrowserZoomState } from './browser-touch-geometry' import { - clampBrowserZoomState, - computeBrowserFrameGeometry, - computeBrowserTouchClickRadiusCss, - mapScreenToBrowserPoint, - readLocalTouchPoint, - type BrowserPoint, - type BrowserTouchLayout, - type BrowserZoomState -} from './browser-touch-geometry' -import { - MAX_ZOOM, - MIN_ZOOM, - assertRpcOk, - browserErrorMessage, - browserFrameMetadataEqual, - buttonColor, - cacheBrowserFrame, clearCachedBrowserFramesForWorktree, - createBrowserFrameDataUri, - createPinchGesture, - getCachedBrowserFrame, makeBrowserFrameCacheKey, peekCachedBrowserFrame, - shouldSurfaceBrowserError, - updateBrowserImageSource, - updateBrowserLayerVisibility, - updatePinchZoom, type FrameLayer, type PinchGesture } from './mobile-browser-frame-state' -import { mobileBrowserPaneStyles as styles } from './mobile-browser-pane-styles' import { displayBrowserUrl, normalizeBrowserUrl } from './browser-url' -import { MobileBrowserAddressField } from './MobileBrowserAddressField' import { resolveMobileBrowserAddressSync } from './mobile-browser-address-sync' +import { MobileBrowserPaneView } from './MobileBrowserPaneView' +import { useMobileBrowserInteractions } from './use-mobile-browser-interactions' +import { useMobileBrowserPaneLayers } from './use-mobile-browser-pane-layers' +import { useMobileBrowserStream } from './use-mobile-browser-stream' export type MobileBrowserTab = { type: 'browser' @@ -108,26 +62,8 @@ type BrowserDialogState = { message: string } -const TAP_SLOP = 16 -const SCROLL_START_SLOP = 22 -const LONG_PRESS_MS = 550 -const WHEEL_INTERVAL_MS = 70 -const TOUCH_CLICK_RADIUS_DIP = 14 const DEFAULT_ZOOM: BrowserZoomState = { scale: 1, offsetX: 0, offsetY: 0 } -type BrowserPageParams = { - worktree: string - page: string -} - -type PendingWheelCommand = { - base: BrowserPageParams - point: BrowserPoint - gestureId: number - dx: number - dy: number -} - export function MobileBrowserPane({ client, worktreeId, @@ -180,17 +116,12 @@ export function MobileBrowserPane({ const frameThrottleTimerRef = useRef | null>(null) const dialogRef = useRef(null) const lastStreamCacheKeyRef = useRef(cacheKey) - const startPointRef = useRef<{ x: number; y: number; t: number } | null>(null) const longPressTimerRef = useRef | null>(null) - const rightClickSentRef = useRef(false) - const lastWheelRef = useRef<{ dx: number; dy: number; at: number }>({ dx: 0, dy: 0, at: 0 }) - const wheelGestureIdRef = useRef(0) - const pendingWheelCommandRef = useRef(null) - const wheelCommandInFlightRef = useRef(false) + const startPointRef = useRef<{ x: number; y: number; t: number } | null>(null) + const scrollingRef = useRef(false) const zoomRef = useRef(DEFAULT_ZOOM) const pinchRef = useRef(null) const panRef = useRef(null) - const scrollingRef = useRef(false) const lastZoomResetUrlRef = useRef(tab.url || 'about:blank') const clearLongPressTimer = useCallback(() => { @@ -265,313 +196,40 @@ export function MobileBrowserPane({ setBrowserViewMode(getInitialMobileBrowserViewMode(worktreeId, tab.browserPageId, tab.url)) }, [tab.browserPageId, tab.url, worktreeId]) - const pageParams = useCallback(() => { - if (!tab.browserPageId) { - return null - } - return { - worktree: `id:${worktreeId}`, - page: tab.browserPageId - } - }, [tab.browserPageId, worktreeId]) - - const applyFrame = useCallback((frame: BrowserScreencastFrame, frameCacheKey: string): void => { - if (!browserFrameMetadataEqual(frameMetadataRef.current, frame.metadata)) { - frameMetadataRef.current = frame.metadata - setFrameMetadata(frame.metadata) - } - const nextFrameUri = createBrowserFrameDataUri(frame) - cacheBrowserFrame(frameCacheKey, { uri: nextFrameUri, metadata: frame.metadata }) - if (!frameMountedRef.current) { - frameUriRef.current = nextFrameUri - frameMountedRef.current = true - setFrameUri(nextFrameUri) - updateBrowserImageSource(browserImageRefs.current[0], nextFrameUri) - } else if (pendingFrameLayerRef.current === null) { - // Why: decode the next frame offscreen and keep the previous layer visible - // until onLoad; replacing the visible Image directly flashes black. - const nextLayer: FrameLayer = visibleFrameLayerRef.current === 0 ? 1 : 0 - frameUriRef.current = nextFrameUri - pendingFrameLayerRef.current = nextLayer - updateBrowserImageSource(browserImageRefs.current[nextLayer], nextFrameUri) - } else { - // Why: popovers/menus can settle in one final frame while the previous - // offscreen frame is still decoding. Keep the hidden layer pointed at - // the newest frame instead of dropping the final static state. - frameUriRef.current = nextFrameUri - updateBrowserImageSource(browserImageRefs.current[pendingFrameLayerRef.current], nextFrameUri) - } - if (busyRef.current) { - busyRef.current = false - setBusy(false) - } - }, []) - - const clearFrameThrottle = useCallback(() => { - pendingThrottledFrameRef.current = null - if (frameThrottleTimerRef.current) { - clearTimeout(frameThrottleTimerRef.current) - frameThrottleTimerRef.current = null - } - }, []) - - const applyFrameThrottled = useCallback( - (frame: BrowserScreencastFrame, frameCacheKey: string): void => { - const now = Date.now() - const elapsed = now - lastAppliedFrameAtRef.current - if (lastAppliedFrameAtRef.current === 0 || elapsed >= MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS) { - clearFrameThrottle() - lastAppliedFrameAtRef.current = now - applyFrame(frame, frameCacheKey) - return - } - - // Why: static UI changes can be the last frame Chromium emits. Coalesce - // throttled frames so the final visible state is applied after the delay. - pendingThrottledFrameRef.current = { frame, cacheKey: frameCacheKey } - if (frameThrottleTimerRef.current) { - return - } - frameThrottleTimerRef.current = setTimeout( - () => { - frameThrottleTimerRef.current = null - const pending = pendingThrottledFrameRef.current - pendingThrottledFrameRef.current = null - if (!pending) { - return - } - lastAppliedFrameAtRef.current = Date.now() - applyFrame(pending.frame, pending.cacheKey) - }, - Math.max(0, MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS - elapsed) - ) - }, - [applyFrame, clearFrameThrottle] - ) - - const streamRequest = useMemo( - () => buildMobileBrowserScreencastRequest(layout, PixelRatio.get(), browserViewMode), - [browserViewMode, layout] - ) - - const frameGeometry = useMemo( - () => computeBrowserFrameGeometry(layout, frameMetadata), - [frameMetadata, layout] - ) - - useEffect(() => { - if (!frameGeometry) { - return - } - setZoom((current) => { - const next = clampBrowserZoomState(current, frameGeometry, MIN_ZOOM, MAX_ZOOM) - if ( - next.scale === current.scale && - next.offsetX === current.offsetX && - next.offsetY === current.offsetY - ) { - return current - } - // Why: rotation/layout changes can shrink the legal pan range while the - // current zoom state still points at the previous viewport geometry. - zoomRef.current = next - return next - }) - }, [frameGeometry]) - - useEffect(() => { - streamGenerationRef.current += 1 - const generation = streamGenerationRef.current - const sameStream = Boolean(cacheKey) && lastStreamCacheKeyRef.current === cacheKey - lastStreamCacheKeyRef.current = cacheKey - if (!sameStream || !frameUriRef.current) { - const cachedFrame = getCachedBrowserFrame(cacheKey) - if (cachedFrame) { - frameUriRef.current = cachedFrame.uri - frameMountedRef.current = true - frameMetadataRef.current = cachedFrame.metadata - setFrameUri(cachedFrame.uri) - setFrameMetadata(cachedFrame.metadata) - } else { - frameUriRef.current = null - frameMountedRef.current = false - setFrameUri(null) - setFrameMetadata(null) - frameMetadataRef.current = null - } - } else { - frameMountedRef.current = true - } - pendingFrameLayerRef.current = null - if (!sameStream || !frameUriRef.current) { - visibleFrameLayerRef.current = 0 - } - updateBrowserLayerVisibility(browserLayerRefs.current, visibleFrameLayerRef.current) - lastAppliedFrameAtRef.current = 0 - clearFrameThrottle() - busyRef.current = false - setDialog(null) - setError(null) - if ( - !client || - screencastSupported !== true || - !tab.browserPageId || - !appActive || - !streamRequest - ) { - busyRef.current = false - setBusy(false) - if (screencastSupported === false) { - setError('Update desktop Orca to stream browser tabs on mobile.') - } else if (screencastSupported === null) { - setError('Checking desktop browser streaming support.') - } else if (!tab.browserPageId) { - setError('Browser page is not available yet.') - } - return - } - busyRef.current = true - setBusy(true) - let startupTimer: ReturnType | null = setTimeout(() => { - if (streamGenerationRef.current !== generation) { - return - } - busyRef.current = false - setBusy(false) - setError('Browser stream timed out.') - }, 15_000) - const clearStartupTimer = (): void => { - if (startupTimer) { - clearTimeout(startupTimer) - startupTimer = null - } - } - const unsubscribe = client.subscribe( - 'browser.screencast', - { - worktree: `id:${worktreeId}`, - page: tab.browserPageId, - ...streamRequest - }, - (payload) => { - if (streamGenerationRef.current !== generation) { - return - } - const event = payload as { - type?: string - message?: string - error?: { message?: string } - dialogType?: string - tab?: { url?: string; title?: string; canGoBack?: boolean; canGoForward?: boolean } - } - if (event.type === 'ready') { - clearStartupTimer() - if (busyRef.current) { - busyRef.current = false - setBusy(false) - } - if (typeof event.tab?.url === 'string') { - setAddressValue(displayBrowserUrl(event.tab.url)) - if (event.tab.url !== lastZoomResetUrlRef.current) { - lastZoomResetUrlRef.current = event.tab.url - resetBrowserZoomState() - } - } - } else if (event.type === 'end') { - clearStartupTimer() - if (busyRef.current) { - busyRef.current = false - setBusy(false) - } - } else if (event.type === 'dialog') { - setDialog({ - dialogType: event.dialogType ?? 'alert', - message: event.message ?? 'Browser dialog' - }) - } else if (event.type === 'dialogClosed') { - setDialog(null) - } else if (event.type === 'error') { - clearStartupTimer() - if (busyRef.current) { - busyRef.current = false - setBusy(false) - } - const message = event.message ?? event.error?.message ?? 'Browser stream failed.' - if (shouldSurfaceBrowserError(message)) { - setError(message) - } - } - }, - { - onBinaryFrame: (frame) => { - if (streamGenerationRef.current !== generation) { - return - } - clearStartupTimer() - if (cacheKey) { - applyFrameThrottled(frame, cacheKey) - } - } - } - ) - return () => { - clearStartupTimer() - clearFrameThrottle() - unsubscribe() - } - }, [ + const { frameGeometry, pageParams, sendBrowserRequest } = useMobileBrowserStream({ appActive, - applyFrameThrottled, - clearFrameThrottle, + browserImageRefs, + browserLayerRefs, + browserViewMode, + busyRef, + cacheKey, client, + frameMetadata, + frameMetadataRef, + frameMountedRef, + frameThrottleTimerRef, + frameUriRef, + lastAppliedFrameAtRef, + lastStreamCacheKeyRef, + lastZoomResetUrlRef, + layout, + pendingFrameLayerRef, + pendingThrottledFrameRef, resetBrowserZoomState, screencastSupported, - streamRequest, - cacheKey, - tab.browserPageId, - worktreeId - ]) - - const sendBrowserRequest = useCallback( - async ( - method: string, - params: Record = {}, - opts: { showBusy?: boolean; suppressError?: boolean; timeoutMs?: number } = {} - ): Promise => { - const base = pageParams() - if (!client || !base) { - return null - } - if (opts.showBusy) { - busyRef.current = true - setBusy(true) - } - try { - const response = await client.sendRequest( - method, - { ...base, ...params }, - { timeoutMs: opts.timeoutMs ?? 15_000 } - ) - if (!response.ok) { - throw new Error((response as RpcFailure).error.message) - } - setError(null) - return (response as RpcSuccess).result - } catch (err) { - const message = browserErrorMessage(err, 'Browser command failed') - if (!opts.suppressError && shouldSurfaceBrowserError(message)) { - setError(message) - } - return null - } finally { - if (opts.showBusy) { - busyRef.current = false - setBusy(false) - } - } - }, - [client, pageParams] - ) + setAddressValue, + setBusy, + setDialog, + setError, + setFrameMetadata, + setFrameUri, + setZoom, + streamGenerationRef, + tab, + visibleFrameLayerRef, + worktreeId, + zoomRef + }) const navigateToAddress = useCallback(async () => { const url = normalizeBrowserUrl(addressValue) @@ -591,411 +249,45 @@ export function MobileBrowserPane({ } }, [addressValue, resetBrowserZoomState, sendBrowserRequest]) - const flushPendingWheelCommand = useCallback(() => { - if (wheelCommandInFlightRef.current) { - return - } - const pending = pendingWheelCommandRef.current - if (!pending || !client) { - return - } - pendingWheelCommandRef.current = null - wheelCommandInFlightRef.current = true - void (async () => { - try { - assertRpcOk( - await client.sendRequest('browser.mouseMove', { - ...pending.base, - x: pending.point.x, - y: pending.point.y - }), - 'Browser pointer move failed' - ) - assertRpcOk( - await client.sendRequest('browser.mouseWheel', { - ...pending.base, - dx: pending.dx, - dy: pending.dy - }), - 'Browser scroll failed' - ) - setError(null) - } catch { - // Scroll bursts commonly race page reload/navigation. Avoid replacing - // the live browser with transient command errors like selector_not_found. - } finally { - wheelCommandInFlightRef.current = false - flushPendingWheelCommand() - } - })() - }, [client]) + const { panResponder, sendDialogCommand, sendKeyboardText, sendKeypress, togglePointerModifier } = + useMobileBrowserInteractions({ + clearLongPressTimer, + client, + dialogRef, + frameGeometry, + frameMetadataRef, + keyboardValue, + layoutRef, + longPressTimerRef, + onToast, + pageParams, + panRef, + pinchRef, + pointerModifiers, + sendBrowserRequest, + scrollingRef, + startPointRef, + setDialog, + setError, + setKeyboardValue, + setPointerModifiers, + setZoom, + zoomRef + }) - const sendPointerClick = useCallback( - async (point: BrowserPoint, button: 'left' | 'right') => { - const base = pageParams() - if (!client || !base) { - return - } - const clickResult = await sendBrowserRequest( - 'browser.mouseClick', - { - x: point.x, - y: point.y, - button, - modifiers: pointerModifiers, - ...(button === 'left' - ? { - radius: computeBrowserTouchClickRadiusCss( - layoutRef.current, - frameMetadataRef.current, - zoomRef.current, - TOUCH_CLICK_RADIUS_DIP - ) - } - : {}) - }, - { suppressError: true, timeoutMs: 5_000 } - ) - if (clickResult !== null || pointerModifiers.length > 0) { - return - } - try { - assertRpcOk( - await client.sendRequest('browser.mouseMove', { ...base, x: point.x, y: point.y }), - 'Browser pointer move failed' - ) - assertRpcOk( - await client.sendRequest('browser.mouseDown', { ...base, button }), - 'Browser pointer down failed' - ) - assertRpcOk( - await client.sendRequest('browser.mouseUp', { ...base, button }), - 'Browser pointer up failed' - ) - setError(null) - } catch { - // Pointer commands can race page navigation. Keep the stream visible; - // actionable failures still surface through navigation/stream errors. - } - }, - [client, pageParams, pointerModifiers, sendBrowserRequest] - ) - - const togglePointerModifier = useCallback((modifier: BrowserPointerModifier) => { - setPointerModifiers((current) => - current.includes(modifier) - ? current.filter((candidate) => candidate !== modifier) - : [...current, modifier] - ) - }, []) - - const sendWheel = useCallback( - (point: BrowserPoint, screenDx: number, screenDy: number) => { - const base = pageParams() - if (!client || !base) { - return - } - const currentLayout = layoutRef.current - const geometry = computeBrowserFrameGeometry(currentLayout, frameMetadataRef.current) - const localZoom = zoomRef.current.scale - const scale = (geometry?.scale ?? 1) * localZoom - const cssDx = screenDx / scale - const cssDy = screenDy / scale - const delta = { dx: Math.round(-cssDx), dy: Math.round(-cssDy) } - if (Math.abs(delta.dx) < 1 && Math.abs(delta.dy) < 1) { - return - } - const pending = pendingWheelCommandRef.current - pendingWheelCommandRef.current = - pending && - pending.base.page === base.page && - pending.gestureId === wheelGestureIdRef.current - ? { - base, - point, - gestureId: wheelGestureIdRef.current, - dx: pending.dx + delta.dx, - dy: pending.dy + delta.dy - } - : { base, point, gestureId: wheelGestureIdRef.current, ...delta } - flushPendingWheelCommand() - }, - [client, flushPendingWheelCommand, pageParams] - ) - - const mapTouchPoint = useCallback((locationX: number, locationY: number): BrowserPoint | null => { - return mapScreenToBrowserPoint( - locationX, - locationY, - layoutRef.current, - frameMetadataRef.current, - zoomRef.current - ) - }, []) - - const handleResponderGrant = useCallback( - (event: GestureResponderEvent) => { - const pinch = createPinchGesture(event, frameGeometry, zoomRef.current) - if (pinch) { - clearLongPressTimer() - pinchRef.current = pinch - panRef.current = null - startPointRef.current = null - return - } - const startPoint = readLocalTouchPoint(event.nativeEvent) - if (!startPoint) { - return - } - startPointRef.current = { x: startPoint.x, y: startPoint.y, t: Date.now() } - rightClickSentRef.current = false - scrollingRef.current = false - wheelGestureIdRef.current += 1 - lastWheelRef.current = { dx: 0, dy: 0, at: 0 } - panRef.current = - zoomRef.current.scale > MIN_ZOOM - ? { - x: startPoint.x, - y: startPoint.y, - offsetX: zoomRef.current.offsetX, - offsetY: zoomRef.current.offsetY - } - : null - clearLongPressTimer() - longPressTimerRef.current = setTimeout(() => { - const start = startPointRef.current - if (!start) { - return - } - const point = mapTouchPoint(start.x, start.y) - if (!point) { - return - } - rightClickSentRef.current = true - void sendPointerClick(point, 'right') - onToast('Right click') - }, LONG_PRESS_MS) - }, - [clearLongPressTimer, frameGeometry, mapTouchPoint, onToast, sendPointerClick] - ) - - const handleResponderMove = useCallback( - (event: GestureResponderEvent, gesture: PanResponderGestureState) => { - const startedPinch = pinchRef.current - ? null - : createPinchGesture(event, frameGeometry, zoomRef.current) - if (startedPinch) { - clearLongPressTimer() - pinchRef.current = startedPinch - panRef.current = null - startPointRef.current = null - } - const activePinch = pinchRef.current - const nextPinch = activePinch ? updatePinchZoom(event, frameGeometry, activePinch) : null - if (nextPinch) { - clearLongPressTimer() - zoomRef.current = nextPinch - setZoom(nextPinch) - return - } - if (activePinch) { - pinchRef.current = null - } - const moved = Math.hypot(gesture.dx, gesture.dy) - if (moved > TAP_SLOP) { - clearLongPressTimer() - } - const activePan = panRef.current - if (activePan && frameGeometry) { - const currentPoint = readLocalTouchPoint(event.nativeEvent) - if (!currentPoint) { - return - } - if (!scrollingRef.current && moved <= TAP_SLOP) { - return - } - scrollingRef.current = true - startPointRef.current = null - const nextZoom = clampBrowserZoomState( - { - scale: zoomRef.current.scale, - offsetX: activePan.offsetX + currentPoint.x - activePan.x, - offsetY: activePan.offsetY + currentPoint.y - activePan.y - }, - frameGeometry, - MIN_ZOOM, - MAX_ZOOM - ) - zoomRef.current = nextZoom - setZoom(nextZoom) - return - } - if (!scrollingRef.current) { - if (moved <= SCROLL_START_SLOP) { - return - } - scrollingRef.current = true - startPointRef.current = null - } - const now = Date.now() - if (now - lastWheelRef.current.at < WHEEL_INTERVAL_MS) { - return - } - const deltaX = gesture.dx - lastWheelRef.current.dx - const deltaY = gesture.dy - lastWheelRef.current.dy - if (Math.abs(deltaX) + Math.abs(deltaY) < 8) { - return - } - const currentPoint = readLocalTouchPoint(event.nativeEvent) - if (!currentPoint) { - return - } - const point = mapTouchPoint(currentPoint.x, currentPoint.y) - if (!point) { - return - } - lastWheelRef.current = { dx: gesture.dx, dy: gesture.dy, at: now } - sendWheel(point, deltaX, deltaY) - }, - [clearLongPressTimer, frameGeometry, mapTouchPoint, sendWheel] - ) - - const handleResponderRelease = useCallback( - (event: GestureResponderEvent, gesture: PanResponderGestureState) => { - clearLongPressTimer() - pinchRef.current = null - panRef.current = null - const start = startPointRef.current - startPointRef.current = null - const wasScrolling = scrollingRef.current - scrollingRef.current = false - if (!start || rightClickSentRef.current || wasScrolling) { - return - } - const moved = Math.hypot(gesture.dx, gesture.dy) - if (moved <= TAP_SLOP && Date.now() - start.t < LONG_PRESS_MS) { - // Why: native browser taps resolve at touch-up. Using touch-down makes - // tiny finger drift feel like the click lands left/up of the finger. - const release = readLocalTouchPoint(event.nativeEvent) ?? start - const point = mapTouchPoint(release.x, release.y) - if (point) { - void sendPointerClick(point, 'left') - } - } - }, - [clearLongPressTimer, mapTouchPoint, sendPointerClick] - ) - - const panResponder = useMemo( - () => - PanResponder.create({ - onStartShouldSetPanResponder: () => dialogRef.current === null, - onMoveShouldSetPanResponder: () => dialogRef.current === null, - onPanResponderGrant: handleResponderGrant, - onPanResponderMove: handleResponderMove, - onPanResponderRelease: handleResponderRelease, - onPanResponderTerminate: () => { - clearLongPressTimer() - pinchRef.current = null - panRef.current = null - scrollingRef.current = false - startPointRef.current = null - }, - onPanResponderTerminationRequest: () => true - }), - [clearLongPressTimer, handleResponderGrant, handleResponderMove, handleResponderRelease] - ) - - const sendKeyboardText = useCallback(async () => { - const text = keyboardValue - if (!text) { - return - } - setKeyboardValue('') - const result = await sendBrowserRequest( - 'browser.keyboardInsertText', - { text }, - { suppressError: true } - ) - if (result !== null) { - onToast('Sent') - } else { - setKeyboardValue(text) - } - }, [keyboardValue, onToast, sendBrowserRequest]) - - const sendKeypress = useCallback( - async (key: string) => { - await sendBrowserRequest('browser.keypress', { key }, { suppressError: true }) - }, - [sendBrowserRequest] - ) - - const sendDialogCommand = useCallback( - async (method: 'browser.dialogAccept' | 'browser.dialogDismiss') => { - setDialog(null) - await sendBrowserRequest(method, {}, { suppressError: true, timeoutMs: 5_000 }) - }, - [sendBrowserRequest] - ) - - const setBrowserImageRef = useCallback((layer: FrameLayer, image: Image | null) => { - browserImageRefs.current[layer] = image - const currentFrameUri = frameUriRef.current - if (image && currentFrameUri) { - updateBrowserImageSource(image, currentFrameUri) - } - }, []) - const setBrowserLayerRef = useCallback((layer: FrameLayer, view: View | null) => { - browserLayerRefs.current[layer] = view - updateBrowserLayerVisibility(browserLayerRefs.current, visibleFrameLayerRef.current) - }, []) - const setBrowserLayer0Ref = useCallback( - (view: View | null) => setBrowserLayerRef(0, view), - [setBrowserLayerRef] - ) - const setBrowserLayer1Ref = useCallback( - (view: View | null) => setBrowserLayerRef(1, view), - [setBrowserLayerRef] - ) - const setBrowserImageLayer0Ref = useCallback( - (image: Image | null) => setBrowserImageRef(0, image), - [setBrowserImageRef] - ) - const setBrowserImageLayer1Ref = useCallback( - (image: Image | null) => setBrowserImageRef(1, image), - [setBrowserImageRef] - ) - - const handleBrowserImageLoad = useCallback((layer: FrameLayer) => { - if (pendingFrameLayerRef.current !== layer) { - return - } - pendingFrameLayerRef.current = null - visibleFrameLayerRef.current = layer - updateBrowserLayerVisibility(browserLayerRefs.current, layer) - }, []) - const handleBrowserImageLayer0Load = useCallback( - () => handleBrowserImageLoad(0), - [handleBrowserImageLoad] - ) - const handleBrowserImageLayer1Load = useCallback( - () => handleBrowserImageLoad(1), - [handleBrowserImageLoad] - ) - const handleBrowserImageError = useCallback((layer: FrameLayer) => { - if (pendingFrameLayerRef.current === layer) { - pendingFrameLayerRef.current = null - } - }, []) - const handleBrowserImageLayer0Error = useCallback( - () => handleBrowserImageError(0), - [handleBrowserImageError] - ) - const handleBrowserImageLayer1Error = useCallback( - () => handleBrowserImageError(1), - [handleBrowserImageError] - ) + const { + browserLayerRef, + frameLayerErrorHandler, + frameLayerLoadHandler, + frameLayerRef, + frameLayerStyle + } = useMobileBrowserPaneLayers({ + browserImageRefs, + browserLayerRefs, + frameUriRef, + pendingFrameLayerRef, + visibleFrameLayerRef + }) const controlsDisabled = !client || !tab.browserPageId || screencastSupported !== true const goBack = useCallback(() => { @@ -1016,6 +308,7 @@ export function MobileBrowserPane({ } void sendBrowserRequest('browser.reload', {}, { suppressError: true }) }, [controlsDisabled, sendBrowserRequest]) + const selectBrowserViewMode = useCallback( (mode: MobileBrowserViewMode) => { if (browserViewMode === mode) { @@ -1028,241 +321,48 @@ export function MobileBrowserPane({ }, [browserViewMode, resetBrowserZoomState, tab.browserPageId, worktreeId] ) + const renderedFrameSource = frameUriRef.current || frameUri ? { uri: frameUriRef.current ?? frameUri! } : null - const frameLayerStyle = useCallback((layer: FrameLayer) => { - return [ - styles.browserImageLayer, - visibleFrameLayerRef.current !== layer && styles.browserImageLayerHidden - ] - }, []) - const browserLayerRef = useCallback( - (layer: FrameLayer) => (layer === 0 ? setBrowserLayer0Ref : setBrowserLayer1Ref), - [setBrowserLayer0Ref, setBrowserLayer1Ref] - ) - const frameLayerRef = useCallback( - (layer: FrameLayer) => (layer === 0 ? setBrowserImageLayer0Ref : setBrowserImageLayer1Ref), - [setBrowserImageLayer0Ref, setBrowserImageLayer1Ref] - ) - const frameLayerLoadHandler = useCallback( - (layer: FrameLayer) => - layer === 0 ? handleBrowserImageLayer0Load : handleBrowserImageLayer1Load, - [handleBrowserImageLayer0Load, handleBrowserImageLayer1Load] - ) - const frameLayerErrorHandler = useCallback( - (layer: FrameLayer) => - layer === 0 ? handleBrowserImageLayer0Error : handleBrowserImageLayer1Error, - [handleBrowserImageLayer0Error, handleBrowserImageLayer1Error] - ) return ( - - - - - - - - - - - - setAddressFocused(true)} - onBlur={() => setAddressFocused(false)} - onSubmit={() => void navigateToAddress()} - focused={addressFocused} - disabled={controlsDisabled} - /> - - - - { - const next = { - width: event.nativeEvent.layout.width, - height: event.nativeEvent.layout.height - } - const current = layoutRef.current - if (current && current.width === next.width && current.height === next.height) { - return - } - layoutRef.current = next - setLayout(next) - }} - {...panResponder.panHandlers} - > - {renderedFrameSource ? ( - - {frameGeometry ? ( - - - {([0, 1] as const).map((layer) => ( - - - - ))} - - - ) : ( - ([0, 1] as const).map((layer) => ( - - - - )) - )} - - ) : null} - {!renderedFrameSource || busy || error ? ( - - {/* Why: a stream can report ready and then deliver no frames, so key the - indicator off actually having pixels or it clears into a blank pane. */} - {busy || (!renderedFrameSource && !error) ? ( - - ) : null} - {error ? {error} : null} - - ) : null} - {dialog ? ( - - - Browser Dialog - {dialog.message} - - {dialog.dialogType !== 'alert' ? ( - [ - styles.dialogButton, - pressed && styles.dialogButtonPressed - ]} - onPress={() => void sendDialogCommand('browser.dialogDismiss')} - > - Cancel - - ) : null} - [ - styles.dialogButton, - styles.dialogButtonPrimary, - pressed && styles.dialogButtonPressed - ]} - onPress={() => void sendDialogCommand('browser.dialogAccept')} - > - OK - - - - - ) : null} - - - - - void sendKeypress(key)} - /> - - void sendKeyboardText()} - /> - void sendKeyboardText()} - accessibilityLabel="Send text to browser" - > - - - - - + ) } diff --git a/mobile/src/browser/MobileBrowserPaneView.tsx b/mobile/src/browser/MobileBrowserPaneView.tsx new file mode 100644 index 00000000000..e36e7044837 --- /dev/null +++ b/mobile/src/browser/MobileBrowserPaneView.tsx @@ -0,0 +1,321 @@ +import type { Dispatch, RefObject, SetStateAction } from 'react' +import { + ActivityIndicator, + Image, + Pressable, + Text, + TextInput, + View, + type PanResponderInstance, + type StyleProp, + type ViewStyle +} from 'react-native' +import { ArrowUp, ChevronLeft, ChevronRight, RefreshCw } from 'lucide-react-native' +import { colors } from '../theme/mobile-theme' +import { MobileBrowserAddressField } from './MobileBrowserAddressField' +import { MobileBrowserKeyRow } from './MobileBrowserKeyRow' +import { + MobileBrowserPointerModifiers, + type BrowserPointerModifier +} from './MobileBrowserPointerModifiers' +import { MobileBrowserToolbarIconButton } from './MobileBrowserToolbarIconButton' +import { MobileBrowserViewModeSwitch } from './MobileBrowserViewModeSwitch' +import { buttonColor, type FrameLayer } from './mobile-browser-frame-state' +import { mobileBrowserPaneStyles as styles } from './mobile-browser-pane-styles' +import type { + BrowserFrameGeometry, + BrowserTouchLayout, + BrowserZoomState +} from './browser-touch-geometry' +import type { MobileBrowserViewMode } from './browser-screencast-request' +import type { MobileBrowserTab } from './MobileBrowserPane' + +type MobileBrowserPaneViewProps = { + addressFocused: boolean + addressValue: string + bottomInset: number + browserLayerRef: (layer: FrameLayer) => (view: View | null) => void + browserViewMode: MobileBrowserViewMode + busy: boolean + controlsDisabled: boolean + dialog: { dialogType: string; message: string } | null + error: string | null + frameGeometry: BrowserFrameGeometry | null + frameLayerErrorHandler: (layer: FrameLayer) => () => void + frameLayerLoadHandler: (layer: FrameLayer) => () => void + frameLayerRef: (layer: FrameLayer) => (image: Image | null) => void + frameLayerStyle: (layer: FrameLayer) => StyleProp + goBack: () => void + goForward: () => void + keyboardLift: number + keyboardValue: string + layoutRef: RefObject + navigateToAddress: () => Promise + panResponder: PanResponderInstance + pointerModifiers: BrowserPointerModifier[] + reloadPage: () => void + renderedFrameSource: { uri: string } | null + selectBrowserViewMode: (mode: MobileBrowserViewMode) => void + sendDialogCommand: (method: 'browser.dialogDismiss' | 'browser.dialogAccept') => Promise + sendKeyboardText: () => Promise + sendKeypress: (key: string) => Promise + setAddressFocused: Dispatch> + setAddressValue: Dispatch> + setKeyboardValue: Dispatch> + setLayout: Dispatch> + setRootViewRef: (view: View | null) => void + tab: MobileBrowserTab + togglePointerModifier: (modifier: BrowserPointerModifier) => void + zoom: BrowserZoomState +} + +export function MobileBrowserPaneView(props: MobileBrowserPaneViewProps) { + const { + addressFocused, + addressValue, + bottomInset, + browserLayerRef, + browserViewMode, + busy, + controlsDisabled, + dialog, + error, + frameGeometry, + frameLayerErrorHandler, + frameLayerLoadHandler, + frameLayerRef, + frameLayerStyle, + goBack, + goForward, + keyboardLift, + keyboardValue, + layoutRef, + navigateToAddress, + panResponder, + pointerModifiers, + reloadPage, + renderedFrameSource, + selectBrowserViewMode, + sendDialogCommand, + sendKeyboardText, + sendKeypress, + setAddressFocused, + setAddressValue, + setKeyboardValue, + setLayout, + setRootViewRef, + tab, + togglePointerModifier, + zoom + } = props + return ( + + + + + + + + + + + + setAddressFocused(true)} + onBlur={() => setAddressFocused(false)} + onSubmit={() => void navigateToAddress()} + focused={addressFocused} + disabled={controlsDisabled} + /> + + + + { + const next = { + width: event.nativeEvent.layout.width, + height: event.nativeEvent.layout.height + } + const current = layoutRef.current + if (current && current.width === next.width && current.height === next.height) { + return + } + layoutRef.current = next + setLayout(next) + }} + {...panResponder.panHandlers} + > + {renderedFrameSource ? ( + + {frameGeometry ? ( + + + {([0, 1] as const).map((layer) => ( + + + + ))} + + + ) : ( + ([0, 1] as const).map((layer) => ( + + + + )) + )} + + ) : null} + {!renderedFrameSource || busy || error ? ( + + {/* Why: a stream can report ready and then deliver no frames, so key the + indicator off actually having pixels or it clears into a blank pane. */} + {busy || (!renderedFrameSource && !error) ? ( + + ) : null} + {error ? {error} : null} + + ) : null} + {dialog ? ( + + + Browser Dialog + {dialog.message} + + {dialog.dialogType !== 'alert' ? ( + [ + styles.dialogButton, + pressed && styles.dialogButtonPressed + ]} + onPress={() => void sendDialogCommand('browser.dialogDismiss')} + > + Cancel + + ) : null} + [ + styles.dialogButton, + styles.dialogButtonPrimary, + pressed && styles.dialogButtonPressed + ]} + onPress={() => void sendDialogCommand('browser.dialogAccept')} + > + OK + + + + + ) : null} + + + + + void sendKeypress(key)} + /> + + void sendKeyboardText()} + /> + void sendKeyboardText()} + accessibilityLabel="Send text to browser" + > + + + + + + ) +} diff --git a/mobile/src/browser/mobile-browser-stream-events.ts b/mobile/src/browser/mobile-browser-stream-events.ts new file mode 100644 index 00000000000..5b65b2987f6 --- /dev/null +++ b/mobile/src/browser/mobile-browser-stream-events.ts @@ -0,0 +1,77 @@ +import type { Dispatch, SetStateAction } from 'react' +import { displayBrowserUrl } from './browser-url' +import { shouldSurfaceBrowserError } from './mobile-browser-frame-state' + +export type BrowserDialogState = { dialogType: string; message: string } + +export type ScreencastEvent = { + type?: string + message?: string + error?: { message?: string } + dialogType?: string + tab?: { url?: string; title?: string; canGoBack?: boolean; canGoForward?: boolean } +} + +type HandleScreencastEventArgs = { + busyRef: { current: boolean } + clearStartupTimer: () => void + event: ScreencastEvent + lastZoomResetUrlRef: { current: string } + resetBrowserZoomState: () => void + setAddressValue: Dispatch> + setBusy: Dispatch> + setDialog: Dispatch> + setError: Dispatch> +} + +export function handleBrowserScreencastEvent(args: HandleScreencastEventArgs): void { + const { + busyRef, + clearStartupTimer, + event, + lastZoomResetUrlRef, + resetBrowserZoomState, + setAddressValue, + setBusy, + setDialog, + setError + } = args + + if (event.type === 'ready') { + clearStartupTimer() + if (busyRef.current) { + busyRef.current = false + setBusy(false) + } + if (typeof event.tab?.url === 'string') { + setAddressValue(displayBrowserUrl(event.tab.url)) + if (event.tab.url !== lastZoomResetUrlRef.current) { + lastZoomResetUrlRef.current = event.tab.url + resetBrowserZoomState() + } + } + } else if (event.type === 'end') { + clearStartupTimer() + if (busyRef.current) { + busyRef.current = false + setBusy(false) + } + } else if (event.type === 'dialog') { + setDialog({ + dialogType: event.dialogType ?? 'alert', + message: event.message ?? 'Browser dialog' + }) + } else if (event.type === 'dialogClosed') { + setDialog(null) + } else if (event.type === 'error') { + clearStartupTimer() + if (busyRef.current) { + busyRef.current = false + setBusy(false) + } + const message = event.message ?? event.error?.message ?? 'Browser stream failed.' + if (shouldSurfaceBrowserError(message)) { + setError(message) + } + } +} diff --git a/mobile/src/browser/use-mobile-browser-commands.ts b/mobile/src/browser/use-mobile-browser-commands.ts new file mode 100644 index 00000000000..30554d4db5f --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-commands.ts @@ -0,0 +1,248 @@ +import { useCallback, useRef, type Dispatch, type SetStateAction } from 'react' +import type { RpcClient } from '../transport/rpc-client' +import type { BrowserScreencastFrameMetadata } from '../transport/browser-screencast-protocol' +import { assertRpcOk } from './mobile-browser-frame-state' +import { + computeBrowserFrameGeometry, + computeBrowserTouchClickRadiusCss, + mapScreenToBrowserPoint, + type BrowserPoint, + type BrowserTouchLayout, + type BrowserZoomState +} from './browser-touch-geometry' +import type { BrowserPointerModifier } from './MobileBrowserPointerModifiers' + +const TOUCH_CLICK_RADIUS_DIP = 14 +type BrowserPageParams = { worktree: string; page: string } +type PendingWheelCommand = { + base: BrowserPageParams + point: BrowserPoint + gestureId: number + dx: number + dy: number +} +type SendBrowserRequest = ( + method: string, + params?: Record, + options?: { showBusy?: boolean; suppressError?: boolean; timeoutMs?: number } +) => Promise + +type MobileBrowserCommandArgs = { + client: RpcClient | null + frameMetadataRef: { current: BrowserScreencastFrameMetadata | null } + keyboardValue: string + layoutRef: { current: BrowserTouchLayout | null } + onToast: (message: string, durationMs?: number) => void + pageParams: () => BrowserPageParams | null + pointerModifiers: BrowserPointerModifier[] + sendBrowserRequest: SendBrowserRequest + setDialog: Dispatch> + setError: Dispatch> + setKeyboardValue: Dispatch> + setPointerModifiers: Dispatch> + zoomRef: { current: BrowserZoomState } +} + +export function useMobileBrowserCommands(args: MobileBrowserCommandArgs) { + const { + client, + frameMetadataRef, + keyboardValue, + layoutRef, + onToast, + pageParams, + pointerModifiers, + sendBrowserRequest, + setDialog, + setError, + setKeyboardValue, + setPointerModifiers, + zoomRef + } = args + + const pendingWheelCommandRef = useRef(null) + + const wheelCommandInFlightRef = useRef(false) + + const flushPendingWheelCommand = useCallback(() => { + if (wheelCommandInFlightRef.current) { + return + } + const pending = pendingWheelCommandRef.current + if (!pending || !client) { + return + } + pendingWheelCommandRef.current = null + wheelCommandInFlightRef.current = true + void (async () => { + try { + assertRpcOk( + await client.sendRequest('browser.mouseMove', { + ...pending.base, + x: pending.point.x, + y: pending.point.y + }), + 'Browser pointer move failed' + ) + assertRpcOk( + await client.sendRequest('browser.mouseWheel', { + ...pending.base, + dx: pending.dx, + dy: pending.dy + }), + 'Browser scroll failed' + ) + setError(null) + } catch { + // Scroll bursts commonly race page reload/navigation. Avoid replacing + // the live browser with transient command errors like selector_not_found. + } finally { + wheelCommandInFlightRef.current = false + flushPendingWheelCommand() + } + })() + }, [client]) + + const sendPointerClick = useCallback( + async (point: BrowserPoint, button: 'left' | 'right') => { + const base = pageParams() + if (!client || !base) { + return + } + const clickResult = await sendBrowserRequest( + 'browser.mouseClick', + { + x: point.x, + y: point.y, + button, + modifiers: pointerModifiers, + ...(button === 'left' + ? { + radius: computeBrowserTouchClickRadiusCss( + layoutRef.current, + frameMetadataRef.current, + zoomRef.current, + TOUCH_CLICK_RADIUS_DIP + ) + } + : {}) + }, + { suppressError: true, timeoutMs: 5_000 } + ) + if (clickResult !== null || pointerModifiers.length > 0) { + return + } + try { + assertRpcOk( + await client.sendRequest('browser.mouseMove', { ...base, x: point.x, y: point.y }), + 'Browser pointer move failed' + ) + assertRpcOk( + await client.sendRequest('browser.mouseDown', { ...base, button }), + 'Browser pointer down failed' + ) + assertRpcOk( + await client.sendRequest('browser.mouseUp', { ...base, button }), + 'Browser pointer up failed' + ) + setError(null) + } catch { + // Pointer commands can race page navigation. Keep the stream visible; + // actionable failures still surface through navigation/stream errors. + } + }, + [client, pageParams, pointerModifiers, sendBrowserRequest] + ) + + const togglePointerModifier = useCallback((modifier: BrowserPointerModifier) => { + setPointerModifiers((current) => + current.includes(modifier) + ? current.filter((candidate) => candidate !== modifier) + : [...current, modifier] + ) + }, []) + + const sendWheel = useCallback( + (point: BrowserPoint, screenDx: number, screenDy: number, gestureId: number) => { + const base = pageParams() + if (!client || !base) { + return + } + const currentLayout = layoutRef.current + const geometry = computeBrowserFrameGeometry(currentLayout, frameMetadataRef.current) + const localZoom = zoomRef.current.scale + const scale = (geometry?.scale ?? 1) * localZoom + const cssDx = screenDx / scale + const cssDy = screenDy / scale + const delta = { dx: Math.round(-cssDx), dy: Math.round(-cssDy) } + if (Math.abs(delta.dx) < 1 && Math.abs(delta.dy) < 1) { + return + } + const pending = pendingWheelCommandRef.current + pendingWheelCommandRef.current = + pending && pending.base.page === base.page && pending.gestureId === gestureId + ? { + base, + point, + gestureId, + dx: pending.dx + delta.dx, + dy: pending.dy + delta.dy + } + : { base, point, gestureId, ...delta } + flushPendingWheelCommand() + }, + [client, flushPendingWheelCommand, pageParams] + ) + + const mapTouchPoint = useCallback((locationX: number, locationY: number): BrowserPoint | null => { + return mapScreenToBrowserPoint( + locationX, + locationY, + layoutRef.current, + frameMetadataRef.current, + zoomRef.current + ) + }, []) + + const sendKeyboardText = useCallback(async () => { + const text = keyboardValue + if (!text) { + return + } + setKeyboardValue('') + const result = await sendBrowserRequest( + 'browser.keyboardInsertText', + { text }, + { suppressError: true } + ) + if (result !== null) { + onToast('Sent') + } else { + setKeyboardValue(text) + } + }, [keyboardValue, onToast, sendBrowserRequest]) + + const sendKeypress = useCallback( + async (key: string) => { + await sendBrowserRequest('browser.keypress', { key }, { suppressError: true }) + }, + [sendBrowserRequest] + ) + + const sendDialogCommand = useCallback( + async (method: 'browser.dialogAccept' | 'browser.dialogDismiss') => { + setDialog(null) + await sendBrowserRequest(method, {}, { suppressError: true, timeoutMs: 5_000 }) + }, + [sendBrowserRequest] + ) + return { + mapTouchPoint, + sendDialogCommand, + sendKeyboardText, + sendKeypress, + sendPointerClick, + sendWheel, + togglePointerModifier + } +} diff --git a/mobile/src/browser/use-mobile-browser-frame-apply.ts b/mobile/src/browser/use-mobile-browser-frame-apply.ts new file mode 100644 index 00000000000..8634edbc924 --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-frame-apply.ts @@ -0,0 +1,122 @@ +import { useCallback, type Dispatch, type SetStateAction } from 'react' +import type { Image } from 'react-native' +import type { + BrowserScreencastFrame, + BrowserScreencastFrameMetadata +} from '../transport/browser-screencast-protocol' +import { MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS } from './browser-screencast-request' +import { + browserFrameMetadataEqual, + cacheBrowserFrame, + createBrowserFrameDataUri, + updateBrowserImageSource, + type FrameLayer +} from './mobile-browser-frame-state' + +type PendingFrame = { frame: BrowserScreencastFrame; cacheKey: string } +type BrowserFrameApplyArgs = { + browserImageRefs: { current: [Image | null, Image | null] } + busyRef: { current: boolean } + frameMetadataRef: { current: BrowserScreencastFrameMetadata | null } + frameMountedRef: { current: boolean } + frameThrottleTimerRef: { current: ReturnType | null } + frameUriRef: { current: string | null } + lastAppliedFrameAtRef: { current: number } + pendingFrameLayerRef: { current: FrameLayer | null } + pendingThrottledFrameRef: { current: PendingFrame | null } + setBusy: Dispatch> + setFrameMetadata: Dispatch> + setFrameUri: Dispatch> + visibleFrameLayerRef: { current: FrameLayer } +} +export function useMobileBrowserFrameApply(args: BrowserFrameApplyArgs) { + const { + browserImageRefs, + busyRef, + frameMetadataRef, + frameMountedRef, + frameThrottleTimerRef, + frameUriRef, + lastAppliedFrameAtRef, + pendingFrameLayerRef, + pendingThrottledFrameRef, + setBusy, + setFrameMetadata, + setFrameUri, + visibleFrameLayerRef + } = args + const applyFrame = useCallback((frame: BrowserScreencastFrame, frameCacheKey: string): void => { + if (!browserFrameMetadataEqual(frameMetadataRef.current, frame.metadata)) { + frameMetadataRef.current = frame.metadata + setFrameMetadata(frame.metadata) + } + const nextFrameUri = createBrowserFrameDataUri(frame) + cacheBrowserFrame(frameCacheKey, { uri: nextFrameUri, metadata: frame.metadata }) + if (!frameMountedRef.current) { + frameUriRef.current = nextFrameUri + frameMountedRef.current = true + setFrameUri(nextFrameUri) + updateBrowserImageSource(browserImageRefs.current[0], nextFrameUri) + } else if (pendingFrameLayerRef.current === null) { + // Why: decode the next frame offscreen and keep the previous layer visible + // until onLoad; replacing the visible Image directly flashes black. + const nextLayer: FrameLayer = visibleFrameLayerRef.current === 0 ? 1 : 0 + frameUriRef.current = nextFrameUri + pendingFrameLayerRef.current = nextLayer + updateBrowserImageSource(browserImageRefs.current[nextLayer], nextFrameUri) + } else { + // Why: popovers/menus can settle in one final frame while the previous + // offscreen frame is still decoding. Keep the hidden layer pointed at + // the newest frame instead of dropping the final static state. + frameUriRef.current = nextFrameUri + updateBrowserImageSource(browserImageRefs.current[pendingFrameLayerRef.current], nextFrameUri) + } + if (busyRef.current) { + busyRef.current = false + setBusy(false) + } + }, []) + + const clearFrameThrottle = useCallback(() => { + pendingThrottledFrameRef.current = null + if (frameThrottleTimerRef.current) { + clearTimeout(frameThrottleTimerRef.current) + frameThrottleTimerRef.current = null + } + }, []) + + const applyFrameThrottled = useCallback( + (frame: BrowserScreencastFrame, frameCacheKey: string): void => { + const now = Date.now() + const elapsed = now - lastAppliedFrameAtRef.current + if (lastAppliedFrameAtRef.current === 0 || elapsed >= MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS) { + clearFrameThrottle() + lastAppliedFrameAtRef.current = now + applyFrame(frame, frameCacheKey) + return + } + + // Why: static UI changes can be the last frame Chromium emits. Coalesce + // throttled frames so the final visible state is applied after the delay. + pendingThrottledFrameRef.current = { frame, cacheKey: frameCacheKey } + if (frameThrottleTimerRef.current) { + return + } + frameThrottleTimerRef.current = setTimeout( + () => { + frameThrottleTimerRef.current = null + const pending = pendingThrottledFrameRef.current + pendingThrottledFrameRef.current = null + if (!pending) { + return + } + lastAppliedFrameAtRef.current = Date.now() + applyFrame(pending.frame, pending.cacheKey) + }, + Math.max(0, MOBILE_BROWSER_FRAME_MIN_INTERVAL_MS - elapsed) + ) + }, + [applyFrame, clearFrameThrottle] + ) + return { applyFrameThrottled, clearFrameThrottle } +} diff --git a/mobile/src/browser/use-mobile-browser-interactions.ts b/mobile/src/browser/use-mobile-browser-interactions.ts new file mode 100644 index 00000000000..519ad45ab3b --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-interactions.ts @@ -0,0 +1,290 @@ +import { useCallback, useMemo, useRef, type Dispatch, type SetStateAction } from 'react' +import { + PanResponder, + type GestureResponderEvent, + type PanResponderGestureState +} from 'react-native' +import type { RpcClient } from '../transport/rpc-client' +import { + createPinchGesture, + MAX_ZOOM, + MIN_ZOOM, + updatePinchZoom, + type PinchGesture +} from './mobile-browser-frame-state' +import { + clampBrowserZoomState, + readLocalTouchPoint, + type BrowserFrameGeometry, + type BrowserTouchLayout, + type BrowserZoomState +} from './browser-touch-geometry' +import type { BrowserPointerModifier } from './MobileBrowserPointerModifiers' +import type { BrowserScreencastFrameMetadata } from '../transport/browser-screencast-protocol' + +import { useMobileBrowserCommands } from './use-mobile-browser-commands' +const TAP_SLOP = 16 +const SCROLL_START_SLOP = 22 +const LONG_PRESS_MS = 550 +const WHEEL_INTERVAL_MS = 70 + +type BrowserPageParams = { worktree: string; page: string } +type PanGesture = { x: number; y: number; offsetX: number; offsetY: number } +type SendBrowserRequest = ( + method: string, + params?: Record, + options?: { showBusy?: boolean; suppressError?: boolean; timeoutMs?: number } +) => Promise + +type MobileBrowserInteractionArgs = { + clearLongPressTimer: () => void + client: RpcClient | null + dialogRef: { current: { dialogType: string; message: string } | null } + frameGeometry: BrowserFrameGeometry | null + frameMetadataRef: { current: BrowserScreencastFrameMetadata | null } + keyboardValue: string + layoutRef: { current: BrowserTouchLayout | null } + longPressTimerRef: { current: ReturnType | null } + onToast: (message: string, durationMs?: number) => void + pageParams: () => BrowserPageParams | null + panRef: { current: PanGesture | null } + pinchRef: { current: PinchGesture | null } + pointerModifiers: BrowserPointerModifier[] + sendBrowserRequest: SendBrowserRequest + setDialog: Dispatch> + setError: Dispatch> + setKeyboardValue: Dispatch> + scrollingRef: { current: boolean } + startPointRef: { current: { x: number; y: number; t: number } | null } + setPointerModifiers: Dispatch> + setZoom: Dispatch> + zoomRef: { current: BrowserZoomState } +} + +export function useMobileBrowserInteractions(args: MobileBrowserInteractionArgs) { + const { + clearLongPressTimer, + client, + dialogRef, + frameGeometry, + frameMetadataRef, + keyboardValue, + layoutRef, + longPressTimerRef, + onToast, + pageParams, + panRef, + pinchRef, + pointerModifiers, + scrollingRef, + sendBrowserRequest, + setDialog, + setError, + setKeyboardValue, + setPointerModifiers, + setZoom, + startPointRef, + zoomRef + } = args + const rightClickSentRef = useRef(false) + const lastWheelRef = useRef({ dx: 0, dy: 0, at: 0 }) + const wheelGestureIdRef = useRef(0) + const { + mapTouchPoint, + sendDialogCommand, + sendKeyboardText, + sendKeypress, + sendPointerClick, + sendWheel, + togglePointerModifier + } = useMobileBrowserCommands({ + client, + frameMetadataRef, + keyboardValue, + layoutRef, + onToast, + pageParams, + pointerModifiers, + sendBrowserRequest, + setDialog, + setError, + setKeyboardValue, + setPointerModifiers, + zoomRef + }) + + const handleResponderGrant = useCallback( + (event: GestureResponderEvent) => { + const pinch = createPinchGesture(event, frameGeometry, zoomRef.current) + if (pinch) { + clearLongPressTimer() + pinchRef.current = pinch + panRef.current = null + startPointRef.current = null + return + } + const startPoint = readLocalTouchPoint(event.nativeEvent) + if (!startPoint) { + return + } + startPointRef.current = { x: startPoint.x, y: startPoint.y, t: Date.now() } + rightClickSentRef.current = false + scrollingRef.current = false + wheelGestureIdRef.current += 1 + lastWheelRef.current = { dx: 0, dy: 0, at: 0 } + panRef.current = + zoomRef.current.scale > MIN_ZOOM + ? { + x: startPoint.x, + y: startPoint.y, + offsetX: zoomRef.current.offsetX, + offsetY: zoomRef.current.offsetY + } + : null + clearLongPressTimer() + longPressTimerRef.current = setTimeout(() => { + const start = startPointRef.current + if (!start) { + return + } + const point = mapTouchPoint(start.x, start.y) + if (!point) { + return + } + rightClickSentRef.current = true + void sendPointerClick(point, 'right') + onToast('Right click') + }, LONG_PRESS_MS) + }, + [clearLongPressTimer, frameGeometry, mapTouchPoint, onToast, sendPointerClick] + ) + + const handleResponderMove = useCallback( + (event: GestureResponderEvent, gesture: PanResponderGestureState) => { + const startedPinch = pinchRef.current + ? null + : createPinchGesture(event, frameGeometry, zoomRef.current) + if (startedPinch) { + clearLongPressTimer() + pinchRef.current = startedPinch + panRef.current = null + startPointRef.current = null + } + const activePinch = pinchRef.current + const nextPinch = activePinch ? updatePinchZoom(event, frameGeometry, activePinch) : null + if (nextPinch) { + clearLongPressTimer() + zoomRef.current = nextPinch + setZoom(nextPinch) + return + } + if (activePinch) { + pinchRef.current = null + } + const moved = Math.hypot(gesture.dx, gesture.dy) + if (moved > TAP_SLOP) { + clearLongPressTimer() + } + const activePan = panRef.current + if (activePan && frameGeometry) { + const currentPoint = readLocalTouchPoint(event.nativeEvent) + if (!currentPoint) { + return + } + if (!scrollingRef.current && moved <= TAP_SLOP) { + return + } + scrollingRef.current = true + startPointRef.current = null + const nextZoom = clampBrowserZoomState( + { + scale: zoomRef.current.scale, + offsetX: activePan.offsetX + currentPoint.x - activePan.x, + offsetY: activePan.offsetY + currentPoint.y - activePan.y + }, + frameGeometry, + MIN_ZOOM, + MAX_ZOOM + ) + zoomRef.current = nextZoom + setZoom(nextZoom) + return + } + if (!scrollingRef.current) { + if (moved <= SCROLL_START_SLOP) { + return + } + scrollingRef.current = true + startPointRef.current = null + } + const now = Date.now() + if (now - lastWheelRef.current.at < WHEEL_INTERVAL_MS) { + return + } + const deltaX = gesture.dx - lastWheelRef.current.dx + const deltaY = gesture.dy - lastWheelRef.current.dy + if (Math.abs(deltaX) + Math.abs(deltaY) < 8) { + return + } + const currentPoint = readLocalTouchPoint(event.nativeEvent) + if (!currentPoint) { + return + } + const point = mapTouchPoint(currentPoint.x, currentPoint.y) + if (!point) { + return + } + lastWheelRef.current = { dx: gesture.dx, dy: gesture.dy, at: now } + sendWheel(point, deltaX, deltaY, wheelGestureIdRef.current) + }, + [clearLongPressTimer, frameGeometry, mapTouchPoint, sendWheel] + ) + + const handleResponderRelease = useCallback( + (event: GestureResponderEvent, gesture: PanResponderGestureState) => { + clearLongPressTimer() + pinchRef.current = null + panRef.current = null + const start = startPointRef.current + startPointRef.current = null + const wasScrolling = scrollingRef.current + scrollingRef.current = false + if (!start || rightClickSentRef.current || wasScrolling) { + return + } + const moved = Math.hypot(gesture.dx, gesture.dy) + if (moved <= TAP_SLOP && Date.now() - start.t < LONG_PRESS_MS) { + // Why: native browser taps resolve at touch-up. Using touch-down makes + // tiny finger drift feel like the click lands left/up of the finger. + const release = readLocalTouchPoint(event.nativeEvent) ?? start + const point = mapTouchPoint(release.x, release.y) + if (point) { + void sendPointerClick(point, 'left') + } + } + }, + [clearLongPressTimer, mapTouchPoint, sendPointerClick] + ) + + const panResponder = useMemo( + () => + PanResponder.create({ + onStartShouldSetPanResponder: () => dialogRef.current === null, + onMoveShouldSetPanResponder: () => dialogRef.current === null, + onPanResponderGrant: handleResponderGrant, + onPanResponderMove: handleResponderMove, + onPanResponderRelease: handleResponderRelease, + onPanResponderTerminate: () => { + clearLongPressTimer() + pinchRef.current = null + panRef.current = null + scrollingRef.current = false + startPointRef.current = null + }, + onPanResponderTerminationRequest: () => true + }), + [clearLongPressTimer, handleResponderGrant, handleResponderMove, handleResponderRelease] + ) + + return { panResponder, sendDialogCommand, sendKeyboardText, sendKeypress, togglePointerModifier } +} diff --git a/mobile/src/browser/use-mobile-browser-pane-layers.ts b/mobile/src/browser/use-mobile-browser-pane-layers.ts new file mode 100644 index 00000000000..a91ca22e71f --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-pane-layers.ts @@ -0,0 +1,141 @@ +import { useCallback } from 'react' +import type { Image, View } from 'react-native' +import { + updateBrowserImageSource, + updateBrowserLayerVisibility, + type FrameLayer +} from './mobile-browser-frame-state' +import { mobileBrowserPaneStyles as styles } from './mobile-browser-pane-styles' + +type BrowserLayerHandlersArgs = { + browserImageRefs: { current: [Image | null, Image | null] } + browserLayerRefs: { current: [View | null, View | null] } + frameUriRef: { current: string | null } + pendingFrameLayerRef: { current: FrameLayer | null } + visibleFrameLayerRef: { current: FrameLayer } +} + +export function useMobileBrowserPaneLayers(args: BrowserLayerHandlersArgs) { + const { + browserImageRefs, + browserLayerRefs, + frameUriRef, + pendingFrameLayerRef, + visibleFrameLayerRef + } = args + + const setBrowserImageRef = useCallback( + (layer: FrameLayer, image: Image | null) => { + browserImageRefs.current[layer] = image + const currentFrameUri = frameUriRef.current + if (image && currentFrameUri) { + updateBrowserImageSource(image, currentFrameUri) + } + }, + [browserImageRefs, frameUriRef] + ) + + const setBrowserLayerRef = useCallback( + (layer: FrameLayer, view: View | null) => { + browserLayerRefs.current[layer] = view + updateBrowserLayerVisibility(browserLayerRefs.current, visibleFrameLayerRef.current) + }, + [browserLayerRefs, visibleFrameLayerRef] + ) + + const setBrowserLayer0Ref = useCallback( + (view: View | null) => setBrowserLayerRef(0, view), + [setBrowserLayerRef] + ) + const setBrowserLayer1Ref = useCallback( + (view: View | null) => setBrowserLayerRef(1, view), + [setBrowserLayerRef] + ) + const setBrowserImageLayer0Ref = useCallback( + (image: Image | null) => setBrowserImageRef(0, image), + [setBrowserImageRef] + ) + const setBrowserImageLayer1Ref = useCallback( + (image: Image | null) => setBrowserImageRef(1, image), + [setBrowserImageRef] + ) + + const handleBrowserImageLoad = useCallback( + (layer: FrameLayer) => { + if (pendingFrameLayerRef.current !== layer) { + return + } + pendingFrameLayerRef.current = null + visibleFrameLayerRef.current = layer + updateBrowserLayerVisibility(browserLayerRefs.current, layer) + }, + [browserLayerRefs, pendingFrameLayerRef, visibleFrameLayerRef] + ) + + const handleBrowserImageLayer0Load = useCallback( + () => handleBrowserImageLoad(0), + [handleBrowserImageLoad] + ) + const handleBrowserImageLayer1Load = useCallback( + () => handleBrowserImageLoad(1), + [handleBrowserImageLoad] + ) + + const handleBrowserImageError = useCallback( + (layer: FrameLayer) => { + if (pendingFrameLayerRef.current === layer) { + pendingFrameLayerRef.current = null + } + }, + [pendingFrameLayerRef] + ) + + const handleBrowserImageLayer0Error = useCallback( + () => handleBrowserImageError(0), + [handleBrowserImageError] + ) + const handleBrowserImageLayer1Error = useCallback( + () => handleBrowserImageError(1), + [handleBrowserImageError] + ) + + const frameLayerStyle = useCallback( + (layer: FrameLayer) => { + return [ + styles.browserImageLayer, + visibleFrameLayerRef.current !== layer && styles.browserImageLayerHidden + ] + }, + [visibleFrameLayerRef] + ) + + const browserLayerRef = useCallback( + (layer: FrameLayer) => (layer === 0 ? setBrowserLayer0Ref : setBrowserLayer1Ref), + [setBrowserLayer0Ref, setBrowserLayer1Ref] + ) + + const frameLayerRef = useCallback( + (layer: FrameLayer) => (layer === 0 ? setBrowserImageLayer0Ref : setBrowserImageLayer1Ref), + [setBrowserImageLayer0Ref, setBrowserImageLayer1Ref] + ) + + const frameLayerLoadHandler = useCallback( + (layer: FrameLayer) => + layer === 0 ? handleBrowserImageLayer0Load : handleBrowserImageLayer1Load, + [handleBrowserImageLayer0Load, handleBrowserImageLayer1Load] + ) + + const frameLayerErrorHandler = useCallback( + (layer: FrameLayer) => + layer === 0 ? handleBrowserImageLayer0Error : handleBrowserImageLayer1Error, + [handleBrowserImageLayer0Error, handleBrowserImageLayer1Error] + ) + + return { + browserLayerRef, + frameLayerErrorHandler, + frameLayerLoadHandler, + frameLayerRef, + frameLayerStyle + } +} diff --git a/mobile/src/browser/use-mobile-browser-request.ts b/mobile/src/browser/use-mobile-browser-request.ts new file mode 100644 index 00000000000..311b9250ff0 --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-request.ts @@ -0,0 +1,67 @@ +import { useCallback, type Dispatch, type SetStateAction } from 'react' +import type { RpcClient } from '../transport/rpc-client' +import type { RpcFailure, RpcSuccess } from '../transport/types' +import { browserErrorMessage, shouldSurfaceBrowserError } from './mobile-browser-frame-state' + +type BrowserRequestArgs = { + busyRef: { current: boolean } + client: RpcClient | null + pageId: string | null + setBusy: Dispatch> + setError: Dispatch> + worktreeId: string +} +export function useMobileBrowserRequest(args: BrowserRequestArgs) { + const { busyRef, client, pageId, setBusy, setError, worktreeId } = args + const pageParams = useCallback(() => { + if (!pageId) { + return null + } + return { + worktree: `id:${worktreeId}`, + page: pageId + } + }, [pageId, worktreeId]) + + const sendBrowserRequest = useCallback( + async ( + method: string, + params: Record = {}, + opts: { showBusy?: boolean; suppressError?: boolean; timeoutMs?: number } = {} + ): Promise => { + const base = pageParams() + if (!client || !base) { + return null + } + if (opts.showBusy) { + busyRef.current = true + setBusy(true) + } + try { + const response = await client.sendRequest( + method, + { ...base, ...params }, + { timeoutMs: opts.timeoutMs ?? 15_000 } + ) + if (!response.ok) { + throw new Error((response as RpcFailure).error.message) + } + setError(null) + return (response as RpcSuccess).result + } catch (err) { + const message = browserErrorMessage(err, 'Browser command failed') + if (!opts.suppressError && shouldSurfaceBrowserError(message)) { + setError(message) + } + return null + } finally { + if (opts.showBusy) { + busyRef.current = false + setBusy(false) + } + } + }, + [client, pageParams] + ) + return { pageParams, sendBrowserRequest } +} diff --git a/mobile/src/browser/use-mobile-browser-stream.ts b/mobile/src/browser/use-mobile-browser-stream.ts new file mode 100644 index 00000000000..5b55dd03ff5 --- /dev/null +++ b/mobile/src/browser/use-mobile-browser-stream.ts @@ -0,0 +1,283 @@ +import { useEffect, useMemo, type Dispatch, type SetStateAction } from 'react' +import { PixelRatio, type Image, type View } from 'react-native' +import type { RpcClient } from '../transport/rpc-client' +import type { + BrowserScreencastFrame, + BrowserScreencastFrameMetadata +} from '../transport/browser-screencast-protocol' +import { + buildMobileBrowserScreencastRequest, + type MobileBrowserViewMode +} from './browser-screencast-request' +import { + MAX_ZOOM, + MIN_ZOOM, + getCachedBrowserFrame, + updateBrowserLayerVisibility, + type FrameLayer +} from './mobile-browser-frame-state' +import { + clampBrowserZoomState, + computeBrowserFrameGeometry, + type BrowserTouchLayout, + type BrowserZoomState +} from './browser-touch-geometry' +import type { MobileBrowserTab } from './MobileBrowserPane' +import { + handleBrowserScreencastEvent, + type BrowserDialogState, + type ScreencastEvent +} from './mobile-browser-stream-events' +import { useMobileBrowserFrameApply } from './use-mobile-browser-frame-apply' +import { useMobileBrowserRequest } from './use-mobile-browser-request' + +type PendingFrame = { frame: BrowserScreencastFrame; cacheKey: string } + +type MobileBrowserStreamArgs = { + appActive: boolean + browserImageRefs: { current: [Image | null, Image | null] } + browserLayerRefs: { current: [View | null, View | null] } + browserViewMode: MobileBrowserViewMode + busyRef: { current: boolean } + cacheKey: string | null + client: RpcClient | null + frameMetadata: BrowserScreencastFrameMetadata | null + frameMetadataRef: { current: BrowserScreencastFrameMetadata | null } + frameMountedRef: { current: boolean } + frameThrottleTimerRef: { current: ReturnType | null } + frameUriRef: { current: string | null } + lastAppliedFrameAtRef: { current: number } + lastStreamCacheKeyRef: { current: string | null } + lastZoomResetUrlRef: { current: string } + layout: BrowserTouchLayout | null + pendingFrameLayerRef: { current: FrameLayer | null } + pendingThrottledFrameRef: { current: PendingFrame | null } + resetBrowserZoomState: () => void + screencastSupported: boolean | null + setAddressValue: Dispatch> + setBusy: Dispatch> + setDialog: Dispatch> + setError: Dispatch> + setFrameMetadata: Dispatch> + setFrameUri: Dispatch> + setZoom: Dispatch> + streamGenerationRef: { current: number } + tab: MobileBrowserTab + visibleFrameLayerRef: { current: FrameLayer } + worktreeId: string + zoomRef: { current: BrowserZoomState } +} + +export function useMobileBrowserStream(args: MobileBrowserStreamArgs) { + const { + appActive, + browserImageRefs, + browserLayerRefs, + browserViewMode, + busyRef, + cacheKey, + client, + frameMetadata, + frameMetadataRef, + frameMountedRef, + frameThrottleTimerRef, + frameUriRef, + lastAppliedFrameAtRef, + lastStreamCacheKeyRef, + lastZoomResetUrlRef, + layout, + pendingFrameLayerRef, + pendingThrottledFrameRef, + resetBrowserZoomState, + screencastSupported, + setAddressValue, + setBusy, + setDialog, + setError, + setFrameMetadata, + setFrameUri, + setZoom, + streamGenerationRef, + tab, + visibleFrameLayerRef, + worktreeId, + zoomRef + } = args + + const { pageParams, sendBrowserRequest } = useMobileBrowserRequest({ + busyRef, + client, + pageId: tab.browserPageId, + setBusy, + setError, + worktreeId + }) + + const { applyFrameThrottled, clearFrameThrottle } = useMobileBrowserFrameApply({ + browserImageRefs, + busyRef, + frameMetadataRef, + frameMountedRef, + frameThrottleTimerRef, + frameUriRef, + lastAppliedFrameAtRef, + pendingFrameLayerRef, + pendingThrottledFrameRef, + setBusy, + setFrameMetadata, + setFrameUri, + visibleFrameLayerRef + }) + + const streamRequest = useMemo( + () => buildMobileBrowserScreencastRequest(layout, PixelRatio.get(), browserViewMode), + [browserViewMode, layout] + ) + + const frameGeometry = useMemo( + () => computeBrowserFrameGeometry(layout, frameMetadata), + [frameMetadata, layout] + ) + + useEffect(() => { + if (!frameGeometry) { + return + } + setZoom((current) => { + const next = clampBrowserZoomState(current, frameGeometry, MIN_ZOOM, MAX_ZOOM) + if ( + next.scale === current.scale && + next.offsetX === current.offsetX && + next.offsetY === current.offsetY + ) { + return current + } + // Why: rotation/layout changes can shrink the legal pan range while the + // current zoom state still points at the previous viewport geometry. + zoomRef.current = next + return next + }) + }, [frameGeometry]) + + useEffect(() => { + streamGenerationRef.current += 1 + const generation = streamGenerationRef.current + const sameStream = Boolean(cacheKey) && lastStreamCacheKeyRef.current === cacheKey + lastStreamCacheKeyRef.current = cacheKey + if (!sameStream || !frameUriRef.current) { + const cachedFrame = getCachedBrowserFrame(cacheKey) + if (cachedFrame) { + frameUriRef.current = cachedFrame.uri + frameMountedRef.current = true + frameMetadataRef.current = cachedFrame.metadata + setFrameUri(cachedFrame.uri) + setFrameMetadata(cachedFrame.metadata) + } else { + frameUriRef.current = null + frameMountedRef.current = false + setFrameUri(null) + setFrameMetadata(null) + frameMetadataRef.current = null + } + } else { + frameMountedRef.current = true + } + pendingFrameLayerRef.current = null + if (!sameStream || !frameUriRef.current) { + visibleFrameLayerRef.current = 0 + } + updateBrowserLayerVisibility(browserLayerRefs.current, visibleFrameLayerRef.current) + lastAppliedFrameAtRef.current = 0 + clearFrameThrottle() + busyRef.current = false + setDialog(null) + setError(null) + if ( + !client || + screencastSupported !== true || + !tab.browserPageId || + !appActive || + !streamRequest + ) { + busyRef.current = false + setBusy(false) + if (screencastSupported === false) { + setError('Update desktop Orca to stream browser tabs on mobile.') + } else if (screencastSupported === null) { + setError('Checking desktop browser streaming support.') + } else if (!tab.browserPageId) { + setError('Browser page is not available yet.') + } + return + } + busyRef.current = true + setBusy(true) + let startupTimer: ReturnType | null = setTimeout(() => { + if (streamGenerationRef.current !== generation) { + return + } + busyRef.current = false + setBusy(false) + setError('Browser stream timed out.') + }, 15_000) + const clearStartupTimer = (): void => { + if (startupTimer) { + clearTimeout(startupTimer) + startupTimer = null + } + } + const unsubscribe = client.subscribe( + 'browser.screencast', + { + worktree: `id:${worktreeId}`, + page: tab.browserPageId, + ...streamRequest + }, + (payload) => { + if (streamGenerationRef.current !== generation) { + return + } + handleBrowserScreencastEvent({ + busyRef, + clearStartupTimer, + event: payload as ScreencastEvent, + lastZoomResetUrlRef, + resetBrowserZoomState, + setAddressValue, + setBusy, + setDialog, + setError + }) + }, + { + onBinaryFrame: (frame) => { + if (streamGenerationRef.current !== generation) { + return + } + clearStartupTimer() + if (cacheKey) { + applyFrameThrottled(frame, cacheKey) + } + } + } + ) + return () => { + clearStartupTimer() + clearFrameThrottle() + unsubscribe() + } + }, [ + appActive, + applyFrameThrottled, + clearFrameThrottle, + client, + resetBrowserZoomState, + screencastSupported, + streamRequest, + cacheKey, + tab.browserPageId, + worktreeId + ]) + + return { frameGeometry, pageParams, sendBrowserRequest } +} diff --git a/mobile/src/diagnostics/troubleshoot-screen-styles.ts b/mobile/src/diagnostics/troubleshoot-screen-styles.ts new file mode 100644 index 00000000000..bf200e3c080 --- /dev/null +++ b/mobile/src/diagnostics/troubleshoot-screen-styles.ts @@ -0,0 +1,134 @@ +import { StyleSheet } from 'react-native' +import { colors, spacing, typography } from '../theme/mobile-theme' + +export const troubleshootScreenStyles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: colors.bgBase, + padding: spacing.lg + }, + topRow: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: spacing.lg + }, + backButton: { + width: 36, + height: 36, + borderRadius: 18, + alignItems: 'center', + justifyContent: 'center', + marginRight: spacing.sm + }, + heading: { + fontSize: 20, + fontWeight: '700', + color: colors.textPrimary + }, + scroll: { + flex: 1 + }, + scrollContent: { + paddingBottom: spacing.xl + }, + diagnosticButton: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: spacing.sm, + backgroundColor: colors.bgRaised, + borderRadius: 10, + paddingVertical: spacing.md, + paddingHorizontal: spacing.lg, + marginBottom: spacing.lg + }, + diagnosticButtonPressed: { + opacity: 0.7 + }, + diagnosticButtonDisabled: { + opacity: 0.5 + }, + diagnosticButtonLabel: { + fontSize: typography.bodySize, + fontWeight: '600', + color: colors.textPrimary + }, + checkRow: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + paddingVertical: spacing.sm + 2, + paddingHorizontal: spacing.md + 2 + }, + checkLabel: { + fontSize: typography.bodySize, + fontWeight: '500', + color: colors.textPrimary + }, + checkDetail: { + flex: 1, + textAlign: 'right', + fontSize: typography.metaSize, + color: colors.textMuted + }, + checkDetailFail: { + color: colors.statusRed + }, + sectionHeading: { + fontSize: typography.metaSize, + fontWeight: '600', + color: colors.textMuted, + textTransform: 'uppercase', + letterSpacing: 0.5, + marginBottom: spacing.sm, + marginTop: spacing.sm, + paddingHorizontal: spacing.xs + }, + section: { + backgroundColor: colors.bgPanel, + borderRadius: 12, + overflow: 'hidden', + marginBottom: spacing.lg + }, + separator: { + height: StyleSheet.hairlineWidth, + backgroundColor: colors.borderSubtle, + marginHorizontal: spacing.md + }, + rowPressed: { + backgroundColor: colors.bgRaised + }, + accordionHeader: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm + 2, + paddingVertical: spacing.md, + paddingHorizontal: spacing.md + 2 + }, + accordionTitle: { + flex: 1, + fontSize: typography.bodySize, + fontWeight: '500', + color: colors.textPrimary + }, + accordionBody: { + paddingHorizontal: spacing.md + 2, + paddingBottom: spacing.md, + gap: spacing.xs + 2 + }, + stepRow: { + flexDirection: 'row', + gap: spacing.sm + }, + bullet: { + fontSize: typography.metaSize, + color: colors.textMuted, + lineHeight: 18 + }, + stepText: { + flex: 1, + fontSize: typography.metaSize, + color: colors.textMuted, + lineHeight: 18 + } +}) diff --git a/mobile/src/files/file-list-fallback.ts b/mobile/src/files/file-list-fallback.ts index ef3041029af..aa7323e13b5 100644 --- a/mobile/src/files/file-list-fallback.ts +++ b/mobile/src/files/file-list-fallback.ts @@ -60,13 +60,10 @@ export function directoryCacheFromFileList(files: LegacyMobileFileEntry[]): Dire Array.from(childrenByDir, ([path, children]) => [ path, { - entries: Array.from( - children, - ([name, isDirectory]): MobileDirEntry => ({ - name, - isDirectory - }) - ) + entries: Array.from(children, ([name, isDirectory]): MobileDirEntry => ({ + name, + isDirectory + })) } ]) ) diff --git a/mobile/src/hooks/use-mobile-dictation-source.test.ts b/mobile/src/hooks/use-mobile-dictation-source.test.ts index 0649e7ee54b..a3192ce86ea 100644 --- a/mobile/src/hooks/use-mobile-dictation-source.test.ts +++ b/mobile/src/hooks/use-mobile-dictation-source.test.ts @@ -95,7 +95,7 @@ describe('useMobileDictation source invariants', () => { /import \{[^}]*createMobileDictationKeepAwakeOwner[^}]*\} from '\.\/mobile-dictation-keep-awake'/ ) expect(source).toContain( - 'const keepAwakeOwner = useMemo(createMobileDictationKeepAwakeOwner, [])' + 'const keepAwakeOwner = useMemo(() => createMobileDictationKeepAwakeOwner(), [])' ) expect(keepAwakeSource).toContain('activateKeepAwakeAsync') expect(keepAwakeSource).toContain('deactivateKeepAwake') diff --git a/mobile/src/hooks/use-mobile-dictation.ts b/mobile/src/hooks/use-mobile-dictation.ts index 648048dc451..7dd1689c94e 100644 --- a/mobile/src/hooks/use-mobile-dictation.ts +++ b/mobile/src/hooks/use-mobile-dictation.ts @@ -26,7 +26,7 @@ export type { UseMobileDictationResult } from './mobile-dictation-session-state' export function useMobileDictation(options: UseMobileDictationOptions): UseMobileDictationResult { const { client, enabled, onTranscript, onError } = options - const keepAwakeOwner = useMemo(createMobileDictationKeepAwakeOwner, []) + const keepAwakeOwner = useMemo(() => createMobileDictationKeepAwakeOwner(), []) const [status, setStatus] = useState('idle') const [error, setError] = useState(null) const activeIdRef = useRef(null) diff --git a/mobile/src/host-screen/host-screen-header.tsx b/mobile/src/host-screen/host-screen-header.tsx new file mode 100644 index 00000000000..8a5caab2858 --- /dev/null +++ b/mobile/src/host-screen/host-screen-header.tsx @@ -0,0 +1,337 @@ +import { Pressable, Text, View } from 'react-native' +import { + ChevronLeft, + Filter, + Layers, + List, + PanelLeftClose, + Plus, + Search, + SlidersHorizontal, + SquareTerminal, + UserCircle, + X +} from 'lucide-react-native' +import { StatusDot } from '../components/StatusDot' +import { classifyConnection, type ConnectionVerdict } from '../transport/connection-health' +import { colors } from '../theme/mobile-theme' +import { hostScreenStyles as styles } from './host-screen-styles' +import type { HostScreenController } from './use-host-screen-controller' + +function isErrorVerdict(v: ConnectionVerdict): boolean { + return v.kind === 'warning' || v.kind === 'unreachable' || v.kind === 'auth-failed' +} + +export function HostScreenHeader({ controller }: { controller: HostScreenController }) { + const { + actions, + connState, + embedded, + floatingWorkspaceEnabled, + forceReconnectHost, + hostId, + lastConnectedAt, + onHideSidebar, + reconnectAttempts, + relayRecovery, + settings, + state + } = controller + + return ( + + + + + + {(() => { + const headerVerdict = classifyConnection({ + state: connState, + reconnectAttempts, + lastConnectedAt, + ...relayRecovery + }) + return ( + <> + + + + {state.hostName || 'Host'} + + + {connState !== 'connected' && + (() => { + // Why: auth-failed has its own banner, so suppress the Reconnect button for that verdict. + const verdict = headerVerdict + const isError = isErrorVerdict(verdict) + const showReconnectButton = isError && hostId && verdict.kind !== 'auth-failed' + if (!showReconnectButton) { + return null + } + return ( + void forceReconnectHost(hostId!)} + hitSlop={8} + > + Reconnect + + ) + })()} + + ) + })()} + {!embedded && floatingWorkspaceEnabled ? ( + + + + ) : null} + {embedded && onHideSidebar ? ( + + + + ) : null} + + + {/* Filter/sort/group toolbar */} + {embedded ? ( + + + 0 && styles.filterChipActive + ]} + onPress={() => state.setShowFilterModal(true)} + accessibilityRole="button" + accessibilityLabel={`Filter workspaces${settings.activeFilterCount > 0 ? `, ${settings.activeFilterCount} active` : ''}`} + > + 0 ? colors.textPrimary : colors.textSecondary} + /> + 0 && styles.filterChipTextActive + ]} + numberOfLines={1} + > + Filter{settings.activeFilterCount > 0 ? ` ${settings.activeFilterCount}` : ''} + + + + state.setShowSortPicker(true)} + accessibilityRole="button" + accessibilityLabel={`Sort by ${settings.selectedSortLabel}`} + > + + + {settings.selectedSortLabel} + + + + state.setShowGroupPicker(true)} + accessibilityRole="button" + accessibilityLabel="Group workspaces" + > + + + {state.groupMode === 'none' + ? 'Group' + : state.groupMode === 'workspaceStatus' + ? 'Status' + : state.groupMode === 'repo' + ? 'Repo' + : 'PR'} + + + + + + actions.navigateFromHostList(`/h/${hostId}/accounts`)} + disabled={connState !== 'connected'} + accessibilityRole="button" + accessibilityLabel="Accounts" + > + + + + actions.navigateFromHostList(`/h/${hostId}/tasks`)} + disabled={connState !== 'connected'} + accessibilityRole="button" + accessibilityLabel="Tasks" + > + + + + {floatingWorkspaceEnabled ? ( + + + + ) : null} + + + + + + state.setShowSearch((s) => !s)} + accessibilityRole="button" + accessibilityLabel={state.showSearch ? 'Close search' : 'Search workspaces'} + > + {state.showSearch ? ( + + ) : ( + + )} + + + + ) : ( + + 0 && styles.filterChipActive]} + onPress={() => state.setShowFilterModal(true)} + > + 0 ? colors.textPrimary : colors.textSecondary} + /> + 0 && styles.filterChipTextActive + ]} + > + Filter{settings.activeFilterCount > 0 ? ` (${settings.activeFilterCount})` : ''} + + + + state.setShowSortPicker(true)}> + + + {settings.selectedSortLabel} + + + + state.setShowGroupPicker(true)}> + + + {state.groupMode === 'none' + ? 'Group' + : state.groupMode === 'workspaceStatus' + ? 'Status' + : state.groupMode === 'repo' + ? 'Repo' + : 'PR'} + + + + + + actions.navigateFromHostList(`/h/${hostId}/accounts`)} + disabled={connState !== 'connected'} + > + + + + actions.navigateFromHostList(`/h/${hostId}/tasks`)} + disabled={connState !== 'connected'} + > + + + + state.setShowSearch((s) => !s)}> + {state.showSearch ? ( + + ) : ( + + )} + + + )} + + ) +} diff --git a/mobile/src/host-screen/host-screen-overlays.tsx b/mobile/src/host-screen/host-screen-overlays.tsx new file mode 100644 index 00000000000..07cbbd58fc5 --- /dev/null +++ b/mobile/src/host-screen/host-screen-overlays.tsx @@ -0,0 +1,231 @@ +import { Pressable, Text, View } from 'react-native' +import { Check, Moon } from 'lucide-react-native' +import { buildWorktreeNavigationActions } from '../agent-history/worktree-navigation-actions' +import { ActionSheetContent } from '../components/ActionSheetModal' +import { BottomDrawer } from '../components/BottomDrawer' +import { ConfirmModal } from '../components/ConfirmModal' +import { NewWorktreeModalController } from '../components/NewWorktreeModalController' +import { PickerModal } from '../components/PickerModal' +import { colors } from '../theme/mobile-theme' +import { hostNewWorktreeSessionRoute } from '../host-route-action-state' +import { getWorktreeRowIdentity } from '../worktree/worktree-host-row-identity' +import { + WORKSPACE_GROUP_OPTIONS as GROUP_OPTIONS, + WORKSPACE_SORT_OPTIONS as SORT_OPTIONS +} from '../worktree/workspace-list-picker-options' +import { isWorktreePinned } from '../worktree/workspace-list-sections' +import { hostScreenStyles as styles } from './host-screen-styles' +import type { HostScreenController } from './use-host-screen-controller' + +export function HostScreenOverlays({ controller }: { controller: HostScreenController }) { + const { + actions, + catalog, + client, + existingWorktreePaths, + hostCapabilities, + hostId, + settings, + showNewWorktree, + state + } = controller + const actionTarget = state.actionTarget + + return ( + <> + state.setShowSortPicker(false)} + /> + + state.setShowGroupPicker(false)} + /> + + state.setShowFilterModal(false)}> + + Filter + {settings.activeFilterCount > 0 && ( + + Clear filters + + )} + + + Workspaces + + + Hide sleeping + {state.filters.hideSleeping && } + + + + Hide default branch + {state.filters.hideDefaultBranch && } + + + + {controller.sectionsResult.uniqueRepos.length > 1 && ( + <> + Repositories + + {controller.sectionsResult.uniqueRepos.map((repo, i) => ( + + {i > 0 && } + settings.toggleRepoFilter(repo.id)} + > + + + {repo.name} + + {state.filters.filterRepoIds.has(repo.id) && ( + + )} + + + ))} + + + )} + + + {/* Worktree long-press action sheet (inline confirm to avoid double-Modal lag) */} + { + state.setConfirmDelete(null) + state.setActionTarget(null) + }} + > + {state.confirmDelete ? ( + + + Delete Worktree + + Delete "{state.confirmDelete.displayName || state.confirmDelete.repo}" ( + {state.confirmDelete.branch})? + + + + [ + styles.confirmBtn, + styles.confirmBtnCancel, + pressed && styles.confirmBtnPressed + ]} + onPress={() => state.setConfirmDelete(null)} + > + Cancel + + [ + styles.confirmBtn, + styles.confirmBtnDestructive, + pressed && styles.confirmBtnPressed + ]} + onPress={() => { + if (state.confirmDelete) { + void actions.handleDeleteWorktree(state.confirmDelete) + } + state.setConfirmDelete(null) + state.setActionTarget(null) + }} + > + Delete + + + + ) : ( + state.setActionTarget(null) + }), + { + label: 'Sleep', + icon: Moon, + onPress: () => { + if (client) { + state.setSleptIds((prev) => + new Set(prev).add(getWorktreeRowIdentity(actionTarget)) + ) + void client + .sendRequest('worktree.sleep', { + worktree: `id:${actionTarget.worktreeId}` + }) + .catch(() => null) + } + state.setActionTarget(null) + } + }, + { + label: isWorktreePinned(actionTarget, state.pinnedIds) ? 'Unpin' : 'Pin', + onPress: () => { + actions.togglePin(actionTarget.worktreeId) + state.setActionTarget(null) + } + }, + { + label: 'Delete', + destructive: true, + onPress: () => state.setConfirmDelete(actionTarget) + } + ] + : [] + } + /> + )} + + + {/* Host remove confirmation */} + void actions.handleRemoveHost()} + onCancel={() => state.setConfirmRemoveHost(false)} + /> + + { + state.newWorktreeModalVisibleRef.current = visible + }} + onCreated={(worktreeId, worktreeName) => { + void catalog.fetchWorktrees({ allowDuringModal: true }) + actions.navigateFromHostList( + hostNewWorktreeSessionRoute(hostId, worktreeId, worktreeName) + ) + }} + onRouteVisibleChange={actions.setShowNewWorktreeVisible} + /> + + ) +} diff --git a/mobile/src/host-screen/host-screen-view.tsx b/mobile/src/host-screen/host-screen-view.tsx new file mode 100644 index 00000000000..e70f07d773a --- /dev/null +++ b/mobile/src/host-screen/host-screen-view.tsx @@ -0,0 +1,25 @@ +import { Text, View } from 'react-native' +import { SafeAreaView } from 'react-native-safe-area-context' +import { hostScreenStyles as styles } from './host-screen-styles' +import { HostScreenHeader } from './host-screen-header' +import { HostScreenOverlays } from './host-screen-overlays' +import { HostWorkspaceList } from './host-workspace-list' +import type { HostScreenController } from './use-host-screen-controller' + +export function HostScreenView({ controller }: { controller: HostScreenController }) { + if (controller.state.error) { + return ( + + {controller.state.error} + + ) + } + + return ( + + + + + + ) +} diff --git a/mobile/src/host-screen/host-workspace-list.tsx b/mobile/src/host-screen/host-workspace-list.tsx new file mode 100644 index 00000000000..13f11780e1c --- /dev/null +++ b/mobile/src/host-screen/host-workspace-list.tsx @@ -0,0 +1,199 @@ +import { Pressable, RefreshControl, SectionList, Text, View } from 'react-native' +import { ChevronDown, ChevronRight, Pin } from 'lucide-react-native' +import { AuthFailedBanner } from '../components/AuthFailedBanner' +import { HostDiagnosticsLink } from '../components/HostDiagnosticsLink' +import { HostRouteNoticeBanner } from '../components/HostRouteNoticeBanner' +import { MobileRepoIcon } from '../components/MobileRepoIcon' +import { MobileSearchField } from '../components/MobileSearchField' +import { NewWorkspaceFab, FAB_SIZE } from '../components/NewWorkspaceFab' +import { WorktreeListRow } from '../components/WorktreeListRow' +import { colors, spacing } from '../theme/mobile-theme' +import { getWorktreeRowIdentity } from '../worktree/worktree-host-row-identity' +import { HostWorkspaceListStates } from '../worktree/host-workspace-list-states' +import { getWorktreeStatus } from '../worktree/workspace-list-sections' +import { repoColor } from '../worktree/repo-color' +import { hostScreenStyles as styles } from './host-screen-styles' +import type { HostScreenController } from './use-host-screen-controller' + +export function HostWorkspaceList({ controller }: { controller: HostScreenController }) { + const { + actions, + activeWorktreeScroll, + catalog, + connState, + contentMaxWidth, + displayWorktrees, + embedded, + forceReconnectHost, + hostId, + insets, + isReadOnly, + isWideLayout, + noticeParam, + now, + reconnectAttempts, + relayRecovery, + routeNotice, + router, + sectionsResult, + setDismissedNotice, + settings, + state + } = controller + const { rawSections, sections, uniqueRepoColors } = sectionsResult + + return ( + <> + {/* Auth failed: a latched relay rejection must reach the same re-pair affordance. */} + {(connState === 'auth-failed' || relayRecovery.pairingRejected) && ( + hostId && void forceReconnectHost(hostId)} + onRepair={() => router.push('/pair-scan')} + onRemove={() => state.setConfirmRemoveHost(true)} + /> + )} + + {connState !== 'connected' && + !relayRecovery.pairingRejected && + reconnectAttempts >= 3 && + hostId ? ( + + router.push({ pathname: '/connection-log', params: { hostId: String(hostId) } }) + } + /> + ) : null} + + {/* Why a bounced route landed here (e.g. the workspace was deleted on the desktop). */} + {routeNotice && ( + setDismissedNotice(noticeParam ?? null)} + /> + )} + + {/* Search bar */} + {state.showSearch && ( + + + + )} + + + + {sections.length > 0 && ( + w.sectionListKey ?? getWorktreeRowIdentity(w)} + stickySectionHeadersEnabled={false} + // Why: keep the search IME up while tapping clear / scrolling results. + keyboardShouldPersistTaps="handled" + keyboardDismissMode="on-drag" + onScrollToIndexFailed={activeWorktreeScroll.onScrollToIndexFailed} + // Why: edge-to-edge under the system nav bar; insets.bottom keeps the last row above it. + contentContainerStyle={[ + styles.list, + // Reserve room so the last row stays tappable above the phone's floating "+" (embedded uses the toolbar +). + { paddingBottom: (embedded ? spacing.lg : FAB_SIZE + spacing.xl) + insets.bottom }, + isWideLayout && + !embedded && { maxWidth: contentMaxWidth, width: '100%', alignSelf: 'center' } + ]} + renderSectionHeader={({ section }) => { + if (!section.title) { + return null + } + const isCollapsed = state.collapsedGroups.has(section.key) + const rawSection = rawSections.find((s) => s.key === section.key) + const count = rawSection?.data.length ?? 0 + const repoSectionColor = + state.groupMode === 'repo' ? uniqueRepoColors.get(section.title) : null + const repoSectionIcon = + state.groupMode === 'repo' ? state.repoIconsByName.get(section.title) : null + return ( + settings.toggleCollapsed(section.key)} + > + {isCollapsed ? ( + + ) : ( + + )} + {section.icon === 'pin' && ( + + )} + {state.groupMode === 'repo' ? ( + + + + ) : null} + {section.title} + {count} + + ) + }} + ItemSeparatorComponent={ListSeparator} + // Why (#8498): manual pull-to-refresh forces a fresh snapshot after a stale-cache reconnect. + refreshControl={ + + } + renderItem={({ item }) => ( + + )} + /> + )} + + {/* Floating "new workspace" button — phone only; embedded sidebars keep the toolbar +. */} + {!embedded && ( + + )} + + ) +} + +function ListSeparator() { + return +} diff --git a/mobile/src/host-screen/use-host-repo-metadata.ts b/mobile/src/host-screen/use-host-repo-metadata.ts new file mode 100644 index 00000000000..a5367a971ad --- /dev/null +++ b/mobile/src/host-screen/use-host-repo-metadata.ts @@ -0,0 +1,85 @@ +import { useCallback } from 'react' +import { setCachedRepos } from '../cache/repo-cache' +import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState, RpcSuccess } from '../transport/types' +import type { RepoSummary } from '../worktree/host-worktree-rpc-types' +import { repoColor } from '../worktree/repo-color' +import type { HostScreenState } from './use-host-screen-state' + +const REPO_METADATA_REFRESH_MS = 60_000 + +export function useHostRepoMetadata(args: { + client: RpcClient | null + connState: ConnectionState + hostId: string | undefined + state: HostScreenState +}) { + const { client, connState, hostId, state } = args + const { + clientRef, + fetchRepoMetadataInFlightRef, + fetchRepoMetadataPendingRef, + repoMetadataFetchedAtRef, + setRepoColorsByName, + setRepoIconsByName, + setRepoIdsByName + } = state + + const fetchRepoMetadata = useCallback( + async (options: { force?: boolean; queueIfInFlight?: boolean } = {}) => { + if (!client || connState !== 'connected' || !hostId) { + return + } + if (fetchRepoMetadataInFlightRef.current.has(client)) { + if (options.queueIfInFlight) { + fetchRepoMetadataPendingRef.current.add(client) + } + return + } + const now = Date.now() + if (!options.force && now - repoMetadataFetchedAtRef.current < REPO_METADATA_REFRESH_MS) { + return + } + fetchRepoMetadataInFlightRef.current.add(client) + const requestClient = client, + requestHostId = hostId + try { + do { + fetchRepoMetadataPendingRef.current.delete(requestClient) + const repoResponse = await requestClient.sendRequest('repo.list') + if (clientRef.current !== requestClient || hostId !== requestHostId || !repoResponse.ok) { + return + } + const repoResult = (repoResponse as RpcSuccess).result as { repos: RepoSummary[] } + repoMetadataFetchedAtRef.current = Date.now() + setCachedRepos(requestHostId, repoResult.repos) + setRepoColorsByName( + new Map( + repoResult.repos.map((repo) => [ + repo.displayName, + repo.badgeColor || repoColor(repo.displayName) + ]) + ) + ) + setRepoIconsByName( + new Map( + repoResult.repos.flatMap((repo) => + repo.repoIcon ? [[repo.displayName, repo.repoIcon] as const] : [] + ) + ) + ) + setRepoIdsByName(new Map(repoResult.repos.map((repo) => [repo.displayName, repo.id]))) + } while (fetchRepoMetadataPendingRef.current.has(requestClient)) + } catch { + // Repo metadata is decorative; the next refresh can retry. + } finally { + fetchRepoMetadataInFlightRef.current.delete(requestClient) + } + }, + [client, connState, hostId] + ) + + return fetchRepoMetadata +} + +export type FetchHostRepoMetadata = ReturnType diff --git a/mobile/src/host-screen/use-host-screen-controller.ts b/mobile/src/host-screen/use-host-screen-controller.ts new file mode 100644 index 00000000000..347fd36a72e --- /dev/null +++ b/mobile/src/host-screen/use-host-screen-controller.ts @@ -0,0 +1,158 @@ +import { useMemo, useState } from 'react' +import { useLocalSearchParams, usePathname, useRouter } from 'expo-router' +import { useSafeAreaInsets } from 'react-native-safe-area-context' +import { useHostProtocolGates } from '../components/HostProtocolGate' +import { visibleHostRouteNotice } from '../host-route-notice' +import { resolveHostRouteActionState } from '../host-route-action-state' +import { useActiveWorktreeScroll } from '../hooks/use-active-worktree-scroll' +import { useNow } from '../hooks/use-now' +import { useResponsiveLayout } from '../layout/responsive-layout' +import { useForgetHostClient, useForceReconnect, useHostClient } from '../transport/client-context' +import { + useLastConnectedAt, + useReconnectAttempt, + useRelayRecoveryStatus +} from '../transport/client-context-connection-metrics' +import { applyWorktreeRowDisplayState } from '../worktree/worktree-host-row-identity' +import { useWorkspaceSections } from '../worktree/use-workspace-sections' +import { useHostRepoMetadata } from './use-host-repo-metadata' +import { useHostScreenIdentity } from './use-host-screen-identity' +import { useHostScreenState } from './use-host-screen-state' +import { useHostViewSettings } from './use-host-view-settings' +import { useHostWorktreeActions } from './use-host-worktree-actions' +import { useHostWorktreeCatalog } from './use-host-worktree-catalog' + +export type HostScreenProps = { + // When true, rendered as the persistent tablet sidebar by the host layout, not as its own routed screen. + embedded?: boolean + // Route params aren't in scope when rendered from the layout, so the caller passes these explicitly. + hostId?: string + action?: string + onHideSidebar?: () => void +} + +export function useHostScreenController({ + embedded = false, + hostId: hostIdProp, + action: actionProp, + onHideSidebar +}: HostScreenProps = {}) { + const params = useLocalSearchParams<{ hostId: string; action?: string; notice?: string }>() + const hostId = hostIdProp ?? params.hostId + const action = actionProp ?? params.action + const [dismissedNotice, setDismissedNotice] = useState(null) + const noticeParam = params.notice?.trim() + const routeNotice = visibleHostRouteNotice(embedded, noticeParam, dismissedNotice) + const router = useRouter() + const pathname = usePathname() + const insets = useSafeAreaInsets() + // Why: cap and center the list on wide/tablet canvases; on phones isWideLayout is false so it stays edge-to-edge. + const { isWideLayout, contentMaxWidth } = useResponsiveLayout() + // Shared client per host owned by RpcClientProvider. See docs/mobile-shared-client-per-host.md. + const { client, state: connState } = useHostClient(hostId) + const reconnectAttempts = useReconnectAttempt(hostId) + const lastConnectedAt = useLastConnectedAt(hostId) + const relayRecovery = useRelayRecoveryStatus(hostId) + const forgetHostClient = useForgetHostClient() + const forceReconnectHost = useForceReconnect() + // One tick drives every visible agent row's relative timestamp. + const now = useNow(30_000) + const { hostCapabilities, floatingWorkspaceEnabled } = useHostProtocolGates() + const state = useHostScreenState(hostId, action) + const settings = useHostViewSettings({ client, connState, hostId, state }) + + useHostScreenIdentity({ client, hostId, state }) + const fetchRepoMetadata = useHostRepoMetadata({ client, connState, hostId, state }) + const catalog = useHostWorktreeCatalog({ + client, + connState, + embedded, + fetchRepoMetadata, + hostId, + state, + syncViewSettingsFromDesktop: settings.syncViewSettingsFromDesktop + }) + const actions = useHostWorktreeActions({ + client, + connState, + embedded, + fetchWorktrees: catalog.fetchWorktrees, + forgetHostClient, + hostId, + pathname, + router, + state + }) + + const resolvedRouteActionState = resolveHostRouteActionState(state.routeActionState, action) + // Why: resolve `action=newWorktree` before commit, but don't reopen after the user closes while the URL persists. + if (resolvedRouteActionState !== state.routeActionState) { + state.setRouteActionState(resolvedRouteActionState) + } + const showNewWorktree = resolvedRouteActionState.showNewWorktree + + const displayWorktrees = useMemo(() => { + // Why: live `worktrees` is authoritative only while connected; under the amber + // mount default, connecting/handshaking must keep the pre-reconnect list too. + const base = connState === 'connected' ? state.worktrees : state.lastKnownWorktrees + return applyWorktreeRowDisplayState( + base, + state.sleptIds, + state.optimisticActiveWorktreeIdentity + ) + }, [ + connState, + state.worktrees, + state.lastKnownWorktrees, + state.sleptIds, + state.optimisticActiveWorktreeIdentity + ]) + const sectionsResult = useWorkspaceSections({ + displayWorktrees, + sortMode: state.sortMode, + filters: state.filters, + search: state.search, + groupMode: state.groupMode, + pinnedIds: state.pinnedIds, + repoIdsByName: state.repoIdsByName, + repoColorsByName: state.repoColorsByName, + collapsedGroups: state.collapsedGroups, + workspaceStatuses: state.workspaceStatuses + }) + const existingWorktreePaths = useMemo(() => state.worktrees.map((w) => w.path), [state.worktrees]) + const activeWorktreeScroll = useActiveWorktreeScroll(sectionsResult.sections) + + return { + actions, + activeWorktreeScroll, + catalog, + client, + connState, + contentMaxWidth, + displayWorktrees, + embedded, + existingWorktreePaths, + floatingWorkspaceEnabled, + forceReconnectHost, + hostCapabilities, + hostId, + insets, + isReadOnly: connState === 'auth-failed', + isWideLayout, + lastConnectedAt, + noticeParam, + now, + onHideSidebar, + reconnectAttempts, + relayRecovery, + routeNotice, + router, + sectionsResult, + setDismissedNotice, + settings, + showNewWorktree, + state + } +} + +export type HostScreenController = ReturnType diff --git a/mobile/src/host-screen/use-host-screen-identity.ts b/mobile/src/host-screen/use-host-screen-identity.ts new file mode 100644 index 00000000000..c0b09f61714 --- /dev/null +++ b/mobile/src/host-screen/use-host-screen-identity.ts @@ -0,0 +1,90 @@ +import { useEffect } from 'react' +import { getCachedWorktrees } from '../cache/worktree-cache' +import { loadPinnedIds } from '../storage/preferences' +import { loadHosts, updateLastConnected } from '../transport/host-store' +import type { RpcClient } from '../transport/rpc-client' +import type { Worktree } from '../worktree/workspace-list-sections' +import type { HostScreenState } from './use-host-screen-state' + +export function useHostScreenIdentity(args: { + client: RpcClient | null + hostId: string | undefined + state: HostScreenState +}): void { + const { client, hostId, state } = args + const { + clientRef, + repoMetadataFetchedAtRef, + setCatalogError, + setError, + setHostName, + setLastKnownWorktrees, + setPinnedIds, + setRepoColorsByName, + setRepoIconsByName, + setWorktrees, + setWorktreesLoaded + } = state + + // Load persisted pins from local cache; view settings are no longer local (they sync via ui.get). + useEffect(() => { + if (!hostId) { + return + } + let stale = false + void (async () => { + const pins = await loadPinnedIds(hostId) + if (stale) { + return + } + setPinnedIds(pins) + })() + return () => { + stale = true + } + }, [hostId]) + + // Why: mirror client into a ref so imperative call sites read it without re-subscribing. + useEffect(() => { + clientRef.current = client + }, [client]) + + useEffect(() => { + setHostName('') + setError('') + setRepoColorsByName(new Map()) + setRepoIconsByName(new Map()) + repoMetadataFetchedAtRef.current = 0 + // Why: useState initializer runs only on first mount, so re-seed the cache when Expo Router reuses this screen for a new hostId. + const freshCache = hostId ? (getCachedWorktrees(hostId) as Worktree[] | null) : null + setCatalogError(null) + if (freshCache) { + setWorktrees(freshCache) + setLastKnownWorktrees(freshCache) + setWorktreesLoaded(true) + } else { + setWorktreesLoaded(false) + setWorktrees([]) + setLastKnownWorktrees([]) + } + if (!hostId) { + return + } + let stale = false + void loadHosts().then((hosts) => { + if (stale) { + return + } + const host = hosts.find((h) => h.id === hostId) + if (!host) { + setError('Host not found') + return + } + setHostName(host.name) + void updateLastConnected(host.id) + }) + return () => { + stale = true + } + }, [hostId]) +} diff --git a/mobile/src/host-screen/use-host-screen-state.ts b/mobile/src/host-screen/use-host-screen-state.ts new file mode 100644 index 00000000000..b27e15ffb91 --- /dev/null +++ b/mobile/src/host-screen/use-host-screen-state.ts @@ -0,0 +1,148 @@ +import { useRef, useState } from 'react' +import type { RepoIcon } from '../../../src/shared/repo-icon' +import type { WorkspaceStatusDefinition } from '../../../src/shared/worktree/types' +import { getCachedWorktrees } from '../cache/worktree-cache' +import { createInitialHostRouteActionState } from '../host-route-action-state' +import type { RpcClient } from '../transport/rpc-client' +import { DEFAULT_MOBILE_WORKSPACE_STATUSES } from '../worktree/mobile-workspace-statuses' +import { WorktreeCatalogSnapshotClient } from '../worktree/worktree-catalog-snapshot-client' +import type { + MobileGroupMode, + MobileSortMode, + MobileViewState +} from '../worktree/workspace-view-settings' +import type { FilterState, Worktree } from '../worktree/workspace-list-sections' + +export function useHostScreenState(hostId: string | undefined, action: string | undefined) { + const [initialCache] = useState(() => + hostId ? (getCachedWorktrees(hostId) as Worktree[] | null) : null + ) + const clientRef = useRef(null) + const fetchWorktreesInFlightRef = useRef(false) + // Why: useRef, not useMemo — React may discard memoized values, which would silently + // reset the snapshot token this object exists to own. + const worktreeCatalogRef = useRef(new WorktreeCatalogSnapshotClient()) + const fetchRepoMetadataInFlightRef = useRef(new WeakSet()) + const fetchRepoMetadataPendingRef = useRef(new WeakSet()) + const repoMetadataFetchedAtRef = useRef(0) + const newWorktreeModalRef = useRef<{ open: () => void }>(null) + const newWorktreeModalVisibleRef = useRef(false) + const [worktrees, setWorktrees] = useState(initialCache ?? []) + const [worktreesLoaded, setWorktreesLoaded] = useState(initialCache != null) + // Why (STA-3123): error code of the last failed worktree.ps, so a broken catalog + // path renders as a failure instead of an empty host. Cleared on the next success. + const [catalogError, setCatalogError] = useState(null) + // Why: track the locally-opened worktree so the active-row highlight moves instantly instead of waiting for the next poll. + const [optimisticActiveWorktreeIdentity, setOptimisticActiveWorktreeIdentity] = useState< + string | null + >(null) + const [repoColorsByName, setRepoColorsByName] = useState>(new Map()) + const [repoIconsByName, setRepoIconsByName] = useState>(new Map()) + const [hostName, setHostName] = useState('') + const [error, setError] = useState('') + const [lastKnownWorktrees, setLastKnownWorktrees] = useState(initialCache ?? []) + const [search, setSearch] = useState('') + const [showSearch, setShowSearch] = useState(false) + const [sortMode, setSortMode] = useState('recent') + const [filters, setFilters] = useState({ + filterRepoIds: new Set(), + hideSleeping: false, + hideDefaultBranch: false, + alwaysShowDefaultBranch: true + }) + const [groupMode, setGroupMode] = useState('repo') + const [workspaceStatuses, setWorkspaceStatuses] = useState( + DEFAULT_MOBILE_WORKSPACE_STATUSES + ) + // displayName → repo id: filters key on repo id, but section headers/rows key on displayName, so bridge the two. + const [repoIdsByName, setRepoIdsByName] = useState>(new Map()) + const [showSortPicker, setShowSortPicker] = useState(false) + const [showGroupPicker, setShowGroupPicker] = useState(false) + const [showFilterModal, setShowFilterModal] = useState(false) + const [actionTarget, setActionTarget] = useState(null) + const [confirmDelete, setConfirmDelete] = useState(null) + const [confirmRemoveHost, setConfirmRemoveHost] = useState(false) + const [routeActionState, setRouteActionState] = useState(() => + createInitialHostRouteActionState(action) + ) + const [sleptIds, setSleptIds] = useState>(new Set()) + const [pinnedIds, setPinnedIds] = useState>(new Set()) + const [collapsedGroups, setCollapsedGroups] = useState>(new Set()) + // Why: ref so the ui.get merge and ui.set writes read the latest values without re-creating callbacks on every state change. + const viewStateRef = useRef({ + groupMode: 'repo', + sortMode: 'recent', + hideSleeping: false, + hideDefaultBranch: false, + alwaysShowDefaultBranch: true, + filterRepoIds: [], + collapsedGroups: [], + workspaceStatuses: DEFAULT_MOBILE_WORKSPACE_STATUSES + }) + + return { + actionTarget, + catalogError, + clientRef, + collapsedGroups, + confirmDelete, + confirmRemoveHost, + error, + fetchRepoMetadataInFlightRef, + fetchRepoMetadataPendingRef, + fetchWorktreesInFlightRef, + filters, + groupMode, + hostName, + lastKnownWorktrees, + newWorktreeModalRef, + newWorktreeModalVisibleRef, + optimisticActiveWorktreeIdentity, + pinnedIds, + repoColorsByName, + repoIconsByName, + repoIdsByName, + repoMetadataFetchedAtRef, + routeActionState, + search, + setActionTarget, + setCatalogError, + setCollapsedGroups, + setConfirmDelete, + setConfirmRemoveHost, + setError, + setFilters, + setGroupMode, + setHostName, + setLastKnownWorktrees, + setOptimisticActiveWorktreeIdentity, + setPinnedIds, + setRepoColorsByName, + setRepoIconsByName, + setRepoIdsByName, + setRouteActionState, + setSearch, + setShowFilterModal, + setShowGroupPicker, + setShowSearch, + setShowSortPicker, + setSleptIds, + setSortMode, + setWorkspaceStatuses, + setWorktrees, + setWorktreesLoaded, + showFilterModal, + showGroupPicker, + showSearch, + showSortPicker, + sleptIds, + sortMode, + viewStateRef, + workspaceStatuses, + worktreeCatalogRef, + worktrees, + worktreesLoaded + } +} + +export type HostScreenState = ReturnType diff --git a/mobile/src/host-screen/use-host-view-settings.ts b/mobile/src/host-screen/use-host-view-settings.ts new file mode 100644 index 00000000000..877aa5f3c9f --- /dev/null +++ b/mobile/src/host-screen/use-host-view-settings.ts @@ -0,0 +1,194 @@ +import { useCallback, useEffect, useMemo } from 'react' +import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState, RpcSuccess } from '../transport/types' +import { getMobileWorkspaceLineageGroupKey } from '../worktree/mobile-workspace-lineage' +import { WORKSPACE_SORT_OPTIONS as SORT_OPTIONS } from '../worktree/workspace-list-picker-options' +import { + applyDesktopViewSettings, + buildWorkspaceViewSettingsUpdate, + type MobileGroupMode, + type MobileSortMode, + type MobileViewState, + type WorkspaceViewSettings +} from '../worktree/workspace-view-settings' +import type { Worktree } from '../worktree/workspace-list-sections' +import type { HostScreenState } from './use-host-screen-state' + +export function useHostViewSettings(args: { + client: RpcClient | null + connState: ConnectionState + hostId: string | undefined + state: HostScreenState +}) { + const { client, connState, hostId, state } = args + const { + clientRef, + collapsedGroups, + filters, + groupMode, + setCollapsedGroups, + setFilters, + setGroupMode, + setSortMode, + setWorkspaceStatuses, + sortMode, + viewStateRef, + workspaceStatuses + } = state + + useEffect(() => { + viewStateRef.current = { + groupMode, + sortMode, + hideSleeping: filters.hideSleeping, + hideDefaultBranch: filters.hideDefaultBranch, + alwaysShowDefaultBranch: filters.alwaysShowDefaultBranch !== false, + filterRepoIds: [...filters.filterRepoIds], + collapsedGroups: [...collapsedGroups], + workspaceStatuses + } + }, [groupMode, sortMode, filters, collapsedGroups, workspaceStatuses]) + + // Apply a MobileViewState onto the individual states and the snapshot ref in one shot. + const applyViewState = useCallback((next: MobileViewState) => { + viewStateRef.current = next + setGroupMode(next.groupMode) + setSortMode(next.sortMode) + setWorkspaceStatuses(next.workspaceStatuses) + setCollapsedGroups(new Set(next.collapsedGroups)) + setFilters({ + filterRepoIds: new Set(next.filterRepoIds), + hideSleeping: next.hideSleeping, + hideDefaultBranch: next.hideDefaultBranch, + alwaysShowDefaultBranch: next.alwaysShowDefaultBranch + }) + }, []) + + // Apply the change locally, then patch the desktop's shared store (ui.set) so both apps stay in sync. + const persistViewSettings = useCallback( + (patch: Partial) => { + const next: MobileViewState = { ...viewStateRef.current, ...patch } + applyViewState(next) + if (!client) { + return + } + // Send only the touched fields: the host merges partial updates, so a stale + // mirror can no longer revert sibling settings another client just changed + // (STA-5781; supersedes the #8873 whole-payload special case). + const payload: WorkspaceViewSettings = buildWorkspaceViewSettingsUpdate(patch, next) + if (Object.keys(payload).length === 0) { + return + } + void client.sendRequest('ui.set', payload).catch(() => { + // Best-effort: view settings are a convenience preference. + }) + }, + [client, applyViewState] + ) + + // Merge the desktop's shared view settings (PersistedUIState) onto local state so desktop changes appear here. + const syncViewSettingsFromDesktop = useCallback(async () => { + if (!client || connState !== 'connected') { + return + } + const requestClient = client + const requestHostId = hostId + try { + const response = await requestClient.sendRequest('ui.get') + if (clientRef.current !== requestClient || hostId !== requestHostId || !response.ok) { + return + } + const ui = ((response as RpcSuccess).result as { ui?: WorkspaceViewSettings }).ui + if (!ui) { + return + } + applyViewState(applyDesktopViewSettings(viewStateRef.current, ui)) + } catch { + // Transient transport failure; retry on the next focus/connect. + } + }, [client, connState, hostId, applyViewState]) + + const handleSortChange = useCallback( + (value: MobileSortMode) => { + persistViewSettings({ sortMode: value }) + }, + [persistViewSettings] + ) + + const toggleHideSleeping = useCallback(() => { + persistViewSettings({ hideSleeping: !viewStateRef.current.hideSleeping }) + }, [persistViewSettings]) + + const toggleHideDefaultBranch = useCallback(() => { + persistViewSettings({ hideDefaultBranch: !viewStateRef.current.hideDefaultBranch }) + }, [persistViewSettings]) + + const toggleRepoFilter = useCallback( + (repoId: string) => { + const next = new Set(viewStateRef.current.filterRepoIds) + if (next.has(repoId)) { + next.delete(repoId) + } else { + next.add(repoId) + } + persistViewSettings({ filterRepoIds: [...next] }) + }, + [persistViewSettings] + ) + + const clearFilters = useCallback(() => { + persistViewSettings({ hideSleeping: false, hideDefaultBranch: false, filterRepoIds: [] }) + }, [persistViewSettings]) + + const activeFilterCount = useMemo(() => { + let count = 0 + if (filters.hideSleeping) { + count++ + } + if (filters.hideDefaultBranch) { + count++ + } + count += filters.filterRepoIds.size + return count + }, [filters]) + const selectedSortLabel = + SORT_OPTIONS.find((option) => option.value === sortMode)?.label ?? 'Recent' + + const handleGroupChange = useCallback( + (value: MobileGroupMode) => { + persistViewSettings({ groupMode: value }) + }, + [persistViewSettings] + ) + + const toggleCollapsed = useCallback( + (key: string) => { + const next = new Set(viewStateRef.current.collapsedGroups) + if (!next.delete(key)) { + next.add(key) + } + persistViewSettings({ collapsedGroups: [...next] }) + }, + [persistViewSettings] + ) + const toggleWorktreeLineage = useCallback( + (item: Worktree) => toggleCollapsed(getMobileWorkspaceLineageGroupKey(item)), + [toggleCollapsed] + ) + + return { + activeFilterCount, + clearFilters, + handleGroupChange, + handleSortChange, + selectedSortLabel, + syncViewSettingsFromDesktop, + toggleCollapsed, + toggleHideDefaultBranch, + toggleHideSleeping, + toggleRepoFilter, + toggleWorktreeLineage + } +} + +export type HostViewSettings = ReturnType diff --git a/mobile/src/host-screen/use-host-worktree-actions.ts b/mobile/src/host-screen/use-host-worktree-actions.ts new file mode 100644 index 00000000000..21f49a4f306 --- /dev/null +++ b/mobile/src/host-screen/use-host-worktree-actions.ts @@ -0,0 +1,212 @@ +import { useCallback } from 'react' +import { Alert } from 'react-native' +import type { useRouter } from 'expo-router' +import { floatingWorkspaceSessionPath } from '../session/floating-workspace' +import { savePinnedIds } from '../storage/preferences' +import type { useForgetHostClient } from '../transport/client-context' +import { removeHostAndCloseClient } from '../transport/host-removal-lifecycle' +import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState } from '../transport/types' +import { setHostRouteNewWorktreeVisible } from '../host-route-action-state' +import { leaveHostRoute } from '../host-route-exit' +import { getWorktreeRowIdentity, removeWorktreeRow } from '../worktree/worktree-host-row-identity' +import { isWorktreePinned, type Worktree } from '../worktree/workspace-list-sections' +import type { HostScreenState } from './use-host-screen-state' + +export function useHostWorktreeActions(args: { + client: RpcClient | null + connState: ConnectionState + embedded: boolean + fetchWorktrees: (options?: { allowDuringModal?: boolean }) => Promise + forgetHostClient: ReturnType + hostId: string | undefined + pathname: string + router: ReturnType + state: HostScreenState +}) { + const { + client, + connState, + embedded, + fetchWorktrees, + forgetHostClient, + hostId, + pathname, + router, + state + } = args + const { + newWorktreeModalRef, + newWorktreeModalVisibleRef, + pinnedIds, + setConfirmRemoveHost, + setLastKnownWorktrees, + setOptimisticActiveWorktreeIdentity, + setPinnedIds, + setRouteActionState, + setWorktrees, + worktrees + } = state + + const leaveHost = useCallback(() => { + leaveHostRoute(router) + }, [router]) + + const openNewWorktreeModal = useCallback(() => { + const modal = newWorktreeModalRef.current + if (!modal) { + return + } + newWorktreeModalVisibleRef.current = true + modal.open() + }, []) + + const setShowNewWorktreeVisible = useCallback((visible: boolean) => { + setRouteActionState((current) => setHostRouteNewWorktreeVisible(current, visible)) + }, []) + + const updateLocalPins = useCallback( + (worktreeId: string, pinned: boolean) => { + setPinnedIds((prev) => { + const next = new Set(prev) + if (pinned) { + next.add(worktreeId) + } else { + next.delete(worktreeId) + } + if (hostId) { + void savePinnedIds(hostId, next) + } + return next + }) + }, + [hostId] + ) + + const togglePin = useCallback( + (worktreeId: string) => { + const worktree = worktrees.find((w) => w.worktreeId === worktreeId) + const currentlyPinned = worktree + ? isWorktreePinned(worktree, pinnedIds) + : pinnedIds.has(worktreeId) + const newPinned = !currentlyPinned + + setWorktrees((prev) => + prev.map((w) => (w.worktreeId === worktreeId ? { ...w, isPinned: newPinned } : w)) + ) + setLastKnownWorktrees((prev) => + prev.map((w) => (w.worktreeId === worktreeId ? { ...w, isPinned: newPinned } : w)) + ) + + updateLocalPins(worktreeId, newPinned) + + if (client) { + client + .sendRequest('worktree.set', { + worktree: `id:${worktreeId}`, + isPinned: newPinned + }) + .catch(() => {}) + } + }, + [client, worktrees, pinnedIds, updateLocalPins] + ) + + const handleDeleteWorktree = useCallback( + async (item: Worktree) => { + if (!client) { + return + } + + const removeFromList = (list: Worktree[]) => removeWorktreeRow(list, item) + setWorktrees(removeFromList) + setLastKnownWorktrees(removeFromList) + + try { + const response = await client.sendRequest('worktree.rm', { + worktree: `id:${item.worktreeId}`, + force: true + }) + if (!response.ok) { + setWorktrees((prev) => [...prev, item]) + setLastKnownWorktrees((prev) => [...prev, item]) + } + void fetchWorktrees() + } catch { + setWorktrees((prev) => [...prev, item]) + setLastKnownWorktrees((prev) => [...prev, item]) + } + }, + [client, fetchWorktrees] + ) + + const handleRemoveHost = useCallback(async () => { + if (!hostId) { + return + } + try { + await removeHostAndCloseClient(hostId, forgetHostClient) + leaveHost() + } catch { + // Why: removal can fail while still paired; re-open confirm (ConfirmModal closes on confirm). + setConfirmRemoveHost(true) + Alert.alert('Could not remove host', 'Please try again.') + } + }, [hostId, leaveHost, forgetHostClient]) + + const navigateFromHostList = useCallback( + (target: string) => { + if (!embedded) { + router.push(target) + return + } + if (pathname === (target.split('?')[0] ?? target)) { + return + } + if (pathname === `/h/${hostId}`) { + router.push(target) + return + } + router.replace(target) + }, + [embedded, hostId, pathname, router] + ) + + const openWorktreeSession = useCallback( + (item: Worktree) => { + setOptimisticActiveWorktreeIdentity(getWorktreeRowIdentity(item)) + if (client && connState === 'connected') { + void client + .sendRequest('worktree.activate', { + worktree: `id:${item.worktreeId}`, + notifyClients: false, + navigation: 'caller' + }) + .catch(() => null) + } + const target = `/h/${hostId}/session/${encodeURIComponent(item.worktreeId)}?name=${encodeURIComponent(item.displayName || item.repo)}` + navigateFromHostList(target) + }, + [client, connState, hostId, navigateFromHostList] + ) + + const openFloatingWorkspace = useCallback(() => { + // Why: no worktree.activate here — the floating sentinel has no worktree + // record; session.tabs.list hydrates its host-owned tabs on open. + navigateFromHostList(floatingWorkspaceSessionPath(hostId)) + }, [hostId, navigateFromHostList]) + + return { + handleDeleteWorktree, + handleRemoveHost, + leaveHost, + navigateFromHostList, + openFloatingWorkspace, + openNewWorktreeModal, + openWorktreeSession, + setShowNewWorktreeVisible, + togglePin + } +} + +export type HostWorktreeActions = ReturnType diff --git a/mobile/src/host-screen/use-host-worktree-catalog.ts b/mobile/src/host-screen/use-host-worktree-catalog.ts new file mode 100644 index 00000000000..9acfed854fa --- /dev/null +++ b/mobile/src/host-screen/use-host-worktree-catalog.ts @@ -0,0 +1,174 @@ +import { useCallback, useEffect } from 'react' +import { useFocusEffect } from 'expo-router' +import { setCachedWorktrees } from '../cache/worktree-cache' +import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState } from '../transport/types' +import { useWorktreeResync } from '../transport/use-worktree-resync' +import { startHostWorktreeRefresh } from '../worktree/host-worktree-refresh' +import { areWorktreeListsEqual } from '../worktree/worktree-list-snapshot' +import { + clearConfirmedActiveWorktreeIdentity, + retainLiveSleptWorktreeIdentities +} from '../worktree/worktree-host-row-identity' +import { savePinnedIds } from '../storage/preferences' +import type { FetchHostRepoMetadata } from './use-host-repo-metadata' +import type { HostScreenState } from './use-host-screen-state' + +export function useHostWorktreeCatalog(args: { + client: RpcClient | null + connState: ConnectionState + embedded: boolean + fetchRepoMetadata: FetchHostRepoMetadata + hostId: string | undefined + state: HostScreenState + syncViewSettingsFromDesktop: () => Promise +}) { + const { + client, + connState, + embedded, + fetchRepoMetadata, + hostId, + state, + syncViewSettingsFromDesktop + } = args + const { + clientRef, + fetchWorktreesInFlightRef, + newWorktreeModalVisibleRef, + setCatalogError, + setLastKnownWorktrees, + setOptimisticActiveWorktreeIdentity, + setPinnedIds, + setSleptIds, + setWorktrees, + setWorktreesLoaded, + worktreeCatalogRef + } = state + + const fetchWorktrees = useCallback( + async (options: { allowDuringModal?: boolean } = {}) => { + if (!client || connState !== 'connected' || !hostId) { + return + } + if (!options.allowDuringModal && newWorktreeModalVisibleRef.current) { + return + } + // Why: prevent slow remote hosts from stacking overlapping worktree.ps requests during polling. + if (fetchWorktreesInFlightRef.current) { + return + } + fetchWorktreesInFlightRef.current = true + const requestClient = client + const requestHostId = hostId + + try { + const fetched = await worktreeCatalogRef.current.fetch(requestClient, requestHostId) + if (clientRef.current !== requestClient || hostId !== requestHostId) { + return + } + if (!options.allowDuringModal && newWorktreeModalVisibleRef.current) { + return + } + // Why (STA-3123): a failed catalog request must not pass for "0 worktrees"; + // surface it so a broken remote host is diagnosable instead of looking empty. + if (fetched.kind === 'request_failed') { + setCatalogError(fetched.code) + return + } + if (fetched.pending.admission.kind === 'invalid') { + setCatalogError('invalid_response') + } + // Why: unchanged responses still yield the confirmed rows, so every poll reasserts + // host truth over optimistic local edits regardless of payload size. + const confirmed = worktreeCatalogRef.current.admit(fetched.pending) + if (confirmed) { + setCatalogError(null) + // Why: reuse the existing array on identical snapshots to keep SectionList/sort rebuilds off the tap path. + setWorktrees((current) => + areWorktreeListsEqual(current, confirmed) ? current : confirmed + ) + setLastKnownWorktrees((current) => + areWorktreeListsEqual(current, confirmed) ? current : confirmed + ) + setWorktreesLoaded(true) + // Why (#8498): overwrite the home-written cache with the confirmed snapshot so a reconnect/remount can't serve a stale list. + if (hostId) { + setCachedWorktrees(hostId, confirmed, { proven: true }) + } + // Drop the optimistic active override once the host reports it active, so later desktop changes win. + setOptimisticActiveWorktreeIdentity((pending) => + clearConfirmedActiveWorktreeIdentity(pending, confirmed) + ) + + // Clear optimistic sleep overrides once the server confirms inactive (liveTerminalCount === 0). + setSleptIds((prev) => retainLiveSleptWorktreeIdentities(prev, confirmed)) + + // Sync pin state from server so desktop-initiated pins reflect without relying on stale AsyncStorage. + const serverPinned = new Set(confirmed.filter((w) => w.isPinned).map((w) => w.worktreeId)) + setPinnedIds((prev) => { + if (serverPinned.size === prev.size && [...serverPinned].every((id) => prev.has(id))) { + return prev + } + if (hostId) { + void savePinnedIds(hostId, serverPinned) + } + return serverPinned + }) + } + } catch { + // Will retry on reconnect + if (clientRef.current === requestClient && hostId === requestHostId) { + setCatalogError('network_error') + } + } finally { + fetchWorktreesInFlightRef.current = false + } + }, + [client, connState, hostId] + ) + + useFocusEffect( + useCallback(() => { + // Why: focus nudges reconnect and probes a possibly half-open socket; empty deps fire per focus, not per state flip (which defeats backoff). + // 'focus' keeps a healthy relay green — probe, never suspend (S2 grey blink). + clientRef.current?.notifyForeground('focus') + }, []) + ) + + const startWorktreeRefresh = useCallback(() => { + if (!client || connState !== 'connected') { + return + } + void syncViewSettingsFromDesktop() + return startHostWorktreeRefresh({ client, fetchWorktrees, fetchRepoMetadata }) + }, [client, connState, fetchWorktrees, fetchRepoMetadata, syncViewSettingsFromDesktop]) + + useFocusEffect( + useCallback(() => { + // The embedded sidebar isn't a routed screen (focus never fires); it refreshes via the mount effect below. + if (!embedded) { + return startWorktreeRefresh() + } + }, [embedded, startWorktreeRefresh]) + ) + + // Why: the embedded sidebar is never the focused route, so wire its refresh lifecycle from a mount effect. + useEffect(() => { + if (embedded) { + return startWorktreeRefresh() + } + }, [embedded, startWorktreeRefresh]) + + // Why (#8498): steady-state polls miss the transition INTO 'connected' after background/sleep, when the cache is stalest. + const { refreshing, onRefresh } = useWorktreeResync({ + client, + connState, + fetchWorktrees, + fetchRepoMetadata + }) + + return { fetchWorktrees, onRefresh, refreshing } +} + +export type HostWorktreeCatalog = ReturnType diff --git a/mobile/src/session/mobile-session-startup-source.test.ts b/mobile/src/session/mobile-session-startup-source.test.ts index 37b1c18971b..7f089b5bcf7 100644 --- a/mobile/src/session/mobile-session-startup-source.test.ts +++ b/mobile/src/session/mobile-session-startup-source.test.ts @@ -9,6 +9,10 @@ const reconciliationHookSource = readFileSync( new URL('./use-mobile-session-tabs-reconciliation.ts', import.meta.url), 'utf8' ) +const terminalInventoryRecoverySource = readFileSync( + new URL('./use-mobile-terminal-inventory-recovery.ts', import.meta.url), + 'utf8' +) const autoCreateHookSource = readFileSync( new URL('./use-initial-session-terminal-autocreate.ts', import.meta.url), 'utf8' @@ -68,25 +72,44 @@ describe('mobile session startup', () => { expect(autoCreateHookSource).toContain('sawSessionTabs: stateRef.current.sawSessionTabs') }) - it('delegates stream ownership while retaining the exact terminal polling cadence', () => { + it('delegates stream ownership while retaining degraded polling and a certified sweep', () => { expect(source).toContain('useMobileSessionTabsReconciliation<') expect(source).toContain('const applicationRevision = ++appliedSessionTabsRevisionRef.current') expect(source).toContain('getApplicationRevision: getSessionTabsApplicationRevision') expect(source).not.toContain("client.subscribe(\n 'session.tabs.subscribe'") expect(reconciliationHookSource).toContain("client.subscribe(\n 'session.tabs.subscribe'") - expect(reconciliationHookSource).toContain( - "if (AppState.currentState !== 'active') {\n controller.setReconciliationActive(false)" - ) - expect(reconciliationHookSource).toContain('void controller.poll()') - expect(reconciliationHookSource).toContain('void fetchTerminals()') + expect(reconciliationHookSource).toContain("if (AppState.currentState !== 'active')") + expect(reconciliationHookSource).toContain('suspendTerminalInventoryRecovery(true)') + expect(reconciliationHookSource).toContain('controller.poll()') + expect(reconciliationHookSource).toContain('tabsRequest !== null') + expect(reconciliationHookSource).toContain('void refreshTerminalInventory()') expect(reconciliationHookSource).toContain("AppState.addEventListener('change'") expect(reconciliationHookSource).toContain('const interval = setInterval(') - expect(reconciliationHookSource).toContain('2000') + expect(reconciliationHookSource).toContain('RECONCILIATION_INTERVAL_MS = 2000') + expect(terminalInventoryRecoverySource).toContain('CERTIFIED_TERMINAL_SWEEP_MS = 60_000') expect(reconciliationHookSource).toContain('controller.setReconciliationActive(false)') expect(reconciliationHookSource).toContain('clearInterval(interval)') expect(reconciliationHookSource).toContain('appStateSubscription.remove()') }) + it('confirms terminal stream teardown with a committed inventory-recovery bridge', () => { + expect(source).toContain("if (data.type === 'end' || data.type === 'error')") + expect(source).toContain('signalTerminalInventoryRecovery()') + expect(terminalInventoryRecoverySource).toContain('actionRef.current = recoveryAction') + expect(terminalInventoryRecoverySource).toContain('pendingSignalScopeRef.current = scopeKey') + expect(terminalInventoryRecoverySource).toContain( + 'committedScope !== null && committedScope !== scopeKey' + ) + expect(source).toContain('return terminalInventoryRequest.activate()') + expect(source).toContain('if (!isCurrent())') + expect(terminalInventoryRecoverySource).toContain( + 'TERMINAL_INVENTORY_CONFIRMATION_DELAY_MS = 750' + ) + expect(terminalInventoryRecoverySource).toContain( + 'refreshTerminalInventory({ allowEmptyLoaded: true })' + ) + }) + it('loads session tabs without waiting for desktop activation', () => { const startupEffect = sliceBetween( 'void (async () => {', diff --git a/mobile/src/session/mobile-session-tabs-stream-health.test.ts b/mobile/src/session/mobile-session-tabs-stream-health.test.ts index 399128bb511..b86e5061fa0 100644 --- a/mobile/src/session/mobile-session-tabs-stream-health.test.ts +++ b/mobile/src/session/mobile-session-tabs-stream-health.test.ts @@ -72,12 +72,10 @@ function makeHarness(options?: { } as unknown as RpcClient const apply = options?.apply ?? - vi.fn( - (value: TestResult): SessionTabsApplyOutcome => ({ - accepted: true, - effectiveTabs: value.tabs - }) - ) + vi.fn((value: TestResult): SessionTabsApplyOutcome => ({ + accepted: true, + effectiveTabs: value.tabs + })) const consumeAccepted = vi.fn() let recoveryNeeded = false const controller = new MobileSessionTabsStreamHealth({ @@ -306,9 +304,8 @@ describe('MobileSessionTabsStreamHealth', () => { }) it('does not consume a rejected stream snapshot or update', () => { - const apply = vi.fn( - (value: TestResult): SessionTabsApplyOutcome => - value.type ? { accepted: false } : { accepted: true, effectiveTabs: value.tabs } + const apply = vi.fn((value: TestResult): SessionTabsApplyOutcome => + value.type ? { accepted: false } : { accepted: true, effectiveTabs: value.tabs } ) const harness = makeHarness({ apply }) const subscription = harness.controller.beginSubscription() diff --git a/mobile/src/session/mobile-terminal-inventory-request.test.ts b/mobile/src/session/mobile-terminal-inventory-request.test.ts new file mode 100644 index 00000000000..a3d0ac926c8 --- /dev/null +++ b/mobile/src/session/mobile-terminal-inventory-request.test.ts @@ -0,0 +1,90 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { MobileTerminalInventoryRequest } from './mobile-terminal-inventory-request' + +function deferred() { + let resolve!: (value: T) => void + let reject!: (reason?: unknown) => void + const promise = new Promise((resolvePromise, rejectPromise) => { + resolve = resolvePromise + reject = rejectPromise + }) + return { promise, reject, resolve } +} + +describe('MobileTerminalInventoryRequest', () => { + afterEach(() => { + vi.restoreAllMocks() + }) + + it('shares an in-flight request and upgrades its empty-list handling', async () => { + const response = deferred() + const execute = vi.fn(async (allowsEmpty: () => boolean) => { + await response.promise + return allowsEmpty() + }) + const requests = new MobileTerminalInventoryRequest() + const startupStarted = vi.fn() + const recoveryStarted = vi.fn() + vi.spyOn(Date, 'now').mockReturnValueOnce(100).mockReturnValue(200) + + const startup = requests.run(false, execute, startupStarted) + const recovery = requests.run(true, execute, recoveryStarted) + expect(recovery).toBe(startup) + expect(startupStarted).toHaveBeenCalledExactlyOnceWith(100) + expect(recoveryStarted).toHaveBeenCalledExactlyOnceWith(100) + await Promise.resolve() + expect(execute).toHaveBeenCalledTimes(1) + + response.resolve() + await expect(startup).resolves.toBe(true) + await expect(recovery).resolves.toBe(true) + }) + + it('starts fresh after the shared request settles or rejects', async () => { + const requests = new MobileTerminalInventoryRequest() + const failure = new Error('transport lost') + + await expect( + requests.run(true, async () => { + throw failure + }) + ).rejects.toBe(failure) + await expect(requests.run(true, async () => true)).resolves.toBe(true) + }) + + it('fences a response after its route activation is replaced', async () => { + const oldResponse = deferred() + const nextResponse = deferred() + const applied: string[] = [] + const oldRequest = new MobileTerminalInventoryRequest() + const deactivateOld = oldRequest.activate() + const oldResult = oldRequest.run(true, async (_allowsEmpty, isCurrent) => { + await oldResponse.promise + if (!isCurrent()) { + return false + } + applied.push('old') + return true + }) + await Promise.resolve() + + deactivateOld() + const nextRequest = new MobileTerminalInventoryRequest() + nextRequest.activate() + const nextResult = nextRequest.run(true, async (_allowsEmpty, isCurrent) => { + await nextResponse.promise + if (!isCurrent()) { + return false + } + applied.push('next') + return true + }) + await Promise.resolve() + + nextResponse.resolve() + await expect(nextResult).resolves.toBe(true) + oldResponse.resolve() + await expect(oldResult).resolves.toBe(false) + expect(applied).toEqual(['next']) + }) +}) diff --git a/mobile/src/session/mobile-terminal-inventory-request.ts b/mobile/src/session/mobile-terminal-inventory-request.ts new file mode 100644 index 00000000000..8257dd5c0c7 --- /dev/null +++ b/mobile/src/session/mobile-terminal-inventory-request.ts @@ -0,0 +1,52 @@ +type InFlightTerminalInventoryRequest = { + allowEmptyLoaded: boolean + promise: Promise + startedAt: number +} + +export class MobileTerminalInventoryRequest { + private activation: symbol | null = null + private inFlight: InFlightTerminalInventoryRequest | null = null + + activate(): () => void { + const activation = Symbol('terminal-inventory-activation') + this.activation = activation + return () => { + if (this.activation === activation) { + this.activation = null + } + } + } + + run( + allowEmptyLoaded: boolean, + execute: (allowsEmpty: () => boolean, isCurrent: () => boolean) => Promise, + onPhysicalRequestStarted?: (startedAt: number) => void + ): Promise { + if (this.inFlight) { + this.inFlight.allowEmptyLoaded ||= allowEmptyLoaded + onPhysicalRequestStarted?.(this.inFlight.startedAt) + return this.inFlight.promise + } + const activation = this.activation + const request: InFlightTerminalInventoryRequest = { + allowEmptyLoaded, + promise: Promise.resolve(false), + startedAt: Date.now() + } + onPhysicalRequestStarted?.(request.startedAt) + const execution = Promise.resolve().then(() => + execute( + () => request.allowEmptyLoaded, + () => activation !== null && this.activation === activation + ) + ) + request.promise = execution.finally(() => { + if (this.inFlight === request) { + this.inFlight = null + } + }) + this.inFlight = request + return request.promise + } +} diff --git a/mobile/src/session/mobile-terminal-records.test.ts b/mobile/src/session/mobile-terminal-records.test.ts index cdcbfaafade..0b2b534df93 100644 --- a/mobile/src/session/mobile-terminal-records.test.ts +++ b/mobile/src/session/mobile-terminal-records.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { getTerminalRecordsFromSessionTabs, + hasConnectedTerminalAbsentFromSessionTabs, mergeTerminalListWithKnownRecords, mergeTerminalRecordsByCurrentOrder, mobileSessionTabsEqual, @@ -150,4 +151,70 @@ describe('mobile terminal records', () => { ) ).toBe(false) }) + + const record = (over: Partial & { handle: string }): TerminalRecord => ({ + title: 'Terminal', + terminalTheme: undefined, + isActive: false, + ...over + }) + const terminalTab = (handle: string): MobileTerminalSessionTab => ({ + id: `tab-${handle}`, + type: 'terminal', + terminal: handle, + title: 'Terminal', + isActive: false + }) + + it('reports a connected terminal the tab snapshot dropped', () => { + const held = [ + record({ handle: 'pty-1', connected: true }), + record({ handle: 'pty-2', connected: true }) + ] + + expect(hasConnectedTerminalAbsentFromSessionTabs(held, [terminalTab('pty-1')])).toBe(true) + }) + + it('ignores parked handles that tabs never carry', () => { + const parked = [ + record({ handle: 'pty-1', connected: false }), + record({ handle: 'pty-2', connected: false }) + ] + + // A worktree with no live PTY lists every parked leaf while tabs publish none; + // treating that as absence would pin the caller to the fast cadence forever. + expect(hasConnectedTerminalAbsentFromSessionTabs(parked, [])).toBe(false) + }) + + it('ignores orphaned PTYs, which have no leaf and so never appear as a tab', () => { + const orphan = [record({ handle: 'pty-1', connected: true, orphaned: true })] + + expect(hasConnectedTerminalAbsentFromSessionTabs(orphan, [])).toBe(false) + }) + + it('ignores a host that omits connected rather than assuming liveness', () => { + expect(hasConnectedTerminalAbsentFromSessionTabs([record({ handle: 'pty-1' })], [])).toBe(false) + }) + + it('clears once the snapshot covers every connected terminal', () => { + const held = [record({ handle: 'pty-1', connected: true })] + + expect( + hasConnectedTerminalAbsentFromSessionTabs(held, [terminalTab('pty-1'), terminalTab('pty-2')]) + ).toBe(false) + }) + + it('keeps the merge additive so absence only schedules the sweep', () => { + const held = [ + record({ handle: 'pty-1', connected: true }), + record({ handle: 'pty-2', connected: true }) + ] + const tabs = [terminalTab('pty-1')] + + expect( + mergeTerminalRecordsByCurrentOrder(getTerminalRecordsFromSessionTabs(tabs), held).map( + (terminal) => terminal.handle + ) + ).toEqual(['pty-1', 'pty-2']) + }) }) diff --git a/mobile/src/session/mobile-terminal-records.ts b/mobile/src/session/mobile-terminal-records.ts index 4a9e4438c84..854513a1a87 100644 --- a/mobile/src/session/mobile-terminal-records.ts +++ b/mobile/src/session/mobile-terminal-records.ts @@ -6,6 +6,10 @@ export type TerminalRecord = { title: string terminalTheme?: MobileTerminalTheme isActive: boolean + /** From `terminal.list`; parked and proven-absent leaves report false. */ + connected?: boolean + /** From `terminal.list`; a live PTY with no leaf, so it never appears as a tab. */ + orphaned?: boolean } export type MobileTerminalSessionTab = { @@ -157,6 +161,26 @@ export function mergeTerminalRecordsByCurrentOrder( ] } +// Why: tab snapshots are partial and can transiently omit a live terminal, so absence +// here is only a hint to schedule the `terminal.list` sweep -- never a reason to prune. +// Restricted to connected, non-orphaned handles: parked leaves and orphaned PTYs are +// legitimately absent from tabs forever and would pin the caller to the fast cadence. +export function hasConnectedTerminalAbsentFromSessionTabs( + currentTerminals: readonly TerminalRecord[], + tabs: readonly MobileSessionTabLike[] +): boolean { + const tabbable = currentTerminals.filter( + (terminal) => terminal.connected === true && terminal.orphaned !== true + ) + if (tabbable.length === 0) { + return false + } + const tabHandles = new Set( + getTerminalRecordsFromSessionTabs(tabs).map((terminal) => terminal.handle) + ) + return tabbable.some((terminal) => !tabHandles.has(terminal.handle)) +} + export function getTerminalRecordsFromSessionTabs( tabs: readonly MobileSessionTabLike[] ): TerminalRecord[] { @@ -169,7 +193,8 @@ export function getTerminalRecordsFromSessionTabs( handle: tab.terminal, title: tab.title || 'Terminal', terminalTheme: tab.terminalTheme, - isActive: tab.isActive === true + isActive: tab.isActive === true, + connected: true } ] }) diff --git a/mobile/src/session/use-mobile-session-tabs-reconciliation.test.ts b/mobile/src/session/use-mobile-session-tabs-reconciliation.test.ts index 33c507f2712..3b419994848 100644 --- a/mobile/src/session/use-mobile-session-tabs-reconciliation.test.ts +++ b/mobile/src/session/use-mobile-session-tabs-reconciliation.test.ts @@ -1,9 +1,11 @@ -import { createElement } from 'react' +import { createElement, useEffect } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState } from '../transport/types' import type { SessionTabsApplyOutcome } from './mobile-session-tabs-stream-health' import { useMobileSessionTabsReconciliation } from './use-mobile-session-tabs-reconciliation' +import type { MobileTerminalInventoryRefreshOptions } from './use-mobile-terminal-inventory-recovery' const lifecycle = vi.hoisted(() => ({ appState: 'active', @@ -38,13 +40,14 @@ type TestResult = { tabs: string[] } -const fetchTerminals = vi.fn(async () => {}) -const applySessionTabs = vi.fn( - (value: TestResult): SessionTabsApplyOutcome => ({ - accepted: true, - effectiveTabs: value.tabs - }) -) +const fetchTerminals = vi.fn(async (options?: MobileTerminalInventoryRefreshOptions) => { + options?.onPhysicalRequestStarted?.(Date.now()) + return true +}) +const applySessionTabs = vi.fn((value: TestResult): SessionTabsApplyOutcome => ({ + accepted: true, + effectiveTabs: value.tabs +})) const consumeAcceptedSessionTabs = vi.fn() let recoveryNeeded = false let clearRecoveryAt = Number.POSITIVE_INFINITY @@ -52,6 +55,9 @@ const hasRecoveryNeed = () => recoveryNeeded const subscribe = vi.fn() const unsubscribe = vi.fn() let streamListener: ((payload: unknown) => void) | null = null +let requestTerminalInventoryRecovery: (() => void) | null = null +let connectionState: ConnectionState = 'connected' +let clientConnectionState: ConnectionState = 'connected' let listSequence = 0 const sendRequest = vi.fn(async () => ({ id: `list-${++listSequence}`, @@ -64,8 +70,17 @@ const sendRequest = vi.fn(async () => ({ })) const client = { sendRequest, - subscribe + subscribe, + getState: () => clientConnectionState } as unknown as RpcClient +const replacementClient = { + sendRequest, + subscribe, + getState: () => clientConnectionState +} as unknown as RpcClient +let currentClient: RpcClient = client +let currentWorktreeId = 'repo::worktree' +let currentTerminalInventoryRecoveryScopeKey = 'host::repo::worktree' function applyWithRecovery(value: TestResult): SessionTabsApplyOutcome { const outcome = applySessionTabs(value) @@ -76,15 +91,24 @@ function applyWithRecovery(value: TestResult): SessionTabsApplyOutcome { } function Harness(): null { - useMobileSessionTabsReconciliation({ - client, - connState: 'connected', - worktreeId: 'repo::worktree', + const actions = useMobileSessionTabsReconciliation({ + client: currentClient, + connState: connectionState, + worktreeId: currentWorktreeId, applySessionTabs: applyWithRecovery, consumeAcceptedSessionTabs, fetchTerminals, + terminalInventoryRecoveryScopeKey: currentTerminalInventoryRecoveryScopeKey, hasRecoveryNeed }) + useEffect(() => { + requestTerminalInventoryRecovery = actions.requestTerminalInventoryRecovery + return () => { + if (requestTerminalInventoryRecovery === actions.requestTerminalInventoryRecovery) { + requestTerminalInventoryRecovery = null + } + } + }, [actions.requestTerminalInventoryRecovery]) return null } @@ -110,6 +134,13 @@ async function setAppState(state: string): Promise { }) } +function expectedRecoveryInventoryOptions() { + return expect.objectContaining({ + allowEmptyLoaded: true, + onPhysicalRequestStarted: expect.any(Function) + }) +} + describe('useMobileSessionTabsReconciliation', () => { let renderer: ReactTestRenderer | null = null async function mount(): Promise { @@ -125,10 +156,19 @@ describe('useMobileSessionTabsReconciliation', () => { lifecycle.appState = 'active' lifecycle.focused = true lifecycle.listeners.clear() + connectionState = 'connected' + clientConnectionState = 'connected' + currentClient = client + currentWorktreeId = 'repo::worktree' + currentTerminalInventoryRecoveryScopeKey = 'host::repo::worktree' recoveryNeeded = false clearRecoveryAt = Number.POSITIVE_INFINITY listSequence = 0 - fetchTerminals.mockClear() + fetchTerminals.mockReset() + fetchTerminals.mockImplementation(async (options?: MobileTerminalInventoryRefreshOptions) => { + options?.onPhysicalRequestStarted?.(Date.now()) + return true + }) applySessionTabs.mockClear() consumeAcceptedSessionTabs.mockClear() unsubscribe.mockClear() @@ -147,10 +187,11 @@ describe('useMobileSessionTabsReconciliation', () => { act(() => renderer?.unmount()) renderer = null streamListener = null + requestTerminalInventoryRecovery = null vi.useRealTimers() }) - it('does zero tab lists and thirty terminal lists in a certified warm minute', async () => { + it('runs one terminal health sweep and zero tab lists in a certified warm minute', async () => { await mount() await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) sendRequest.mockClear() @@ -161,7 +202,275 @@ describe('useMobileSessionTabsReconciliation', () => { }) expect(sendRequest).not.toHaveBeenCalled() - expect(fetchTerminals).toHaveBeenCalledTimes(30) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + }) + + it('backs off a failed certified terminal sweep for another minute', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + fetchTerminals.mockResolvedValue(false) + + await act(async () => { + await vi.advanceTimersByTimeAsync(60_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + await act(async () => { + await vi.advanceTimersByTimeAsync(58_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + await act(async () => { + await vi.advanceTimersByTimeAsync(2_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + }) + + it('coalesces terminal teardown into two separated inventory passes', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + + await act(async () => { + requestTerminalInventoryRecovery?.() + requestTerminalInventoryRecovery?.() + requestTerminalInventoryRecovery?.() + await flush() + }) + + expect(fetchTerminals).toHaveBeenCalledExactlyOnceWith(expectedRecoveryInventoryOptions()) + await act(async () => { + await vi.advanceTimersByTimeAsync(749) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + await act(async () => { + await vi.advanceTimersByTimeAsync(1) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + expect(fetchTerminals).toHaveBeenLastCalledWith(expectedRecoveryInventoryOptions()) + }) + + it('moves the certified sweep deadline after teardown recovery', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + + await act(async () => { + await vi.advanceTimersByTimeAsync(59_000) + requestTerminalInventoryRecovery?.() + await flush() + await vi.advanceTimersByTimeAsync(1_000) + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(2) + expect(fetchTerminals).toHaveBeenNthCalledWith(1, expectedRecoveryInventoryOptions()) + expect(fetchTerminals).toHaveBeenNthCalledWith(2, expectedRecoveryInventoryOptions()) + }) + + it.each(['failure', 'rejection'] as const)( + 'does not confirm terminal absence after an unverifiable first-pass %s', + async (outcome) => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + if (outcome === 'failure') { + fetchTerminals.mockResolvedValueOnce(false) + } else { + fetchTerminals.mockRejectedValueOnce(new Error('transport lost')) + } + + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + await vi.advanceTimersByTimeAsync(750) + }) + + expect(fetchTerminals).toHaveBeenCalledExactlyOnceWith(expectedRecoveryInventoryOptions()) + } + ) + + it.each(['background', 'blur', 'disconnect', 'socket-loss', 'unmount'] as const)( + 'cancels terminal inventory confirmation on %s', + async (lifecycleChange) => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + if (lifecycleChange === 'background') { + await setAppState('background') + } else if (lifecycleChange === 'blur') { + lifecycle.focused = false + await act(async () => { + renderer?.update(createElement(Harness)) + await flush() + }) + } else if (lifecycleChange === 'disconnect') { + connectionState = 'disconnected' + await act(async () => { + renderer?.update(createElement(Harness)) + await flush() + }) + } else if (lifecycleChange === 'socket-loss') { + clientConnectionState = 'disconnected' + } else { + await act(async () => { + renderer?.unmount() + await flush() + }) + renderer = null + } + + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + } + ) + + it('resumes a pending terminal confirmation after returning to the foreground', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + await setAppState('background') + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + await setAppState('active') + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(4) + expect(fetchTerminals).toHaveBeenNthCalledWith(3, expectedRecoveryInventoryOptions()) + expect(fetchTerminals).toHaveBeenNthCalledWith(4, expectedRecoveryInventoryOptions()) + }) + + it('resumes pending terminal recovery after a silent socket reconnect', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + clientConnectionState = 'disconnected' + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + clientConnectionState = 'connected' + await act(async () => { + await vi.advanceTimersByTimeAsync(1_250) + await vi.advanceTimersByTimeAsync(750) + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(3) + expect(fetchTerminals).toHaveBeenNthCalledWith(2, expectedRecoveryInventoryOptions()) + expect(fetchTerminals).toHaveBeenNthCalledWith(3, expectedRecoveryInventoryOptions()) + }) + + it('resumes a pending terminal confirmation after controller replacement', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + currentClient = replacementClient + await act(async () => { + renderer?.update(createElement(Harness)) + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(3) + + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(4) + expect(fetchTerminals).toHaveBeenLastCalledWith(expectedRecoveryInventoryOptions()) + }) + + it('drops pending terminal confirmation when the route identity changes', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + fetchTerminals.mockClear() + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + currentWorktreeId = 'repo::other-worktree' + currentTerminalInventoryRecoveryScopeKey = 'host::repo::other-worktree' + await act(async () => { + renderer?.update(createElement(Harness)) + await flush() + }) + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(2) + expect(fetchTerminals).toHaveBeenLastCalledWith( + expect.objectContaining({ onPhysicalRequestStarted: expect.any(Function) }) + ) + }) + + it('starts replacement-tab polling after confirmed terminal inventory absence', async () => { + await mount() + await emitStream({ type: 'updated', snapshotVersion: 1, tabs: ['tab-1'] }) + sendRequest.mockClear() + fetchTerminals.mockClear() + clearRecoveryAt = 4_000 + let successfulEmptyInventories = 0 + let terminalPruned = false + fetchTerminals.mockImplementation(async () => { + successfulEmptyInventories += 1 + if (successfulEmptyInventories === 2) { + terminalPruned = true + recoveryNeeded = true + } + return true + }) + + await act(async () => { + requestTerminalInventoryRecovery?.() + await flush() + }) + expect(terminalPruned).toBe(false) + + await act(async () => { + await vi.advanceTimersByTimeAsync(750) + }) + expect(successfulEmptyInventories).toBe(2) + expect(terminalPruned).toBe(true) + + await act(async () => { + await vi.advanceTimersByTimeAsync(5_250) + }) + + expect(sendRequest).toHaveBeenCalledTimes(2) + expect(recoveryNeeded).toBe(false) }) it('runs an immediate list plus five fallback lists over ten probing seconds', async () => { @@ -262,7 +571,7 @@ describe('useMobileSessionTabsReconciliation', () => { }) expect(sendRequest).toHaveBeenCalledTimes(5) - expect(fetchTerminals).toHaveBeenCalledTimes(6) + expect(fetchTerminals).toHaveBeenCalledTimes(5) expect(recoveryNeeded).toBe(false) }) diff --git a/mobile/src/session/use-mobile-session-tabs-reconciliation.ts b/mobile/src/session/use-mobile-session-tabs-reconciliation.ts index 277fc77ac47..18858d31026 100644 --- a/mobile/src/session/use-mobile-session-tabs-reconciliation.ts +++ b/mobile/src/session/use-mobile-session-tabs-reconciliation.ts @@ -9,6 +9,10 @@ import { type SessionTabsStreamSource } from './mobile-session-tabs-stream-health' import { PendingTerminalHandleRecoveryBudget } from './pending-terminal-handle-recovery' +import { + useMobileTerminalInventoryRecovery, + type MobileTerminalInventoryRefreshOptions +} from './use-mobile-terminal-inventory-recovery' type Params = { client: RpcClient | null @@ -20,7 +24,8 @@ type Params = { effectiveTabs: readonly Tab[], source: SessionTabsStreamSource ) => void - fetchTerminals: () => Promise + fetchTerminals: (options?: MobileTerminalInventoryRefreshOptions) => Promise + terminalInventoryRecoveryScopeKey: string hasRecoveryNeed: () => boolean pendingTerminalRecoveryContextKey?: string | null getPendingTerminalRecoveryContextKey?: () => string | null @@ -37,9 +42,11 @@ type ResultActions = { ensureSessionTabs: () => Promise fetchPendingBrowserSessionTabs: () => Promise retryPendingTerminalRecovery: () => Promise + requestTerminalInventoryRecovery: () => void } const resolved = Promise.resolve() +const RECONCILIATION_INTERVAL_MS = 2000 export function useMobileSessionTabsReconciliation({ client, @@ -48,6 +55,7 @@ export function useMobileSessionTabsReconciliation({ applySessionTabs, consumeAcceptedSessionTabs, fetchTerminals, + terminalInventoryRecoveryScopeKey, hasRecoveryNeed, pendingTerminalRecoveryContextKey, getPendingTerminalRecoveryContextKey, @@ -122,11 +130,27 @@ export function useMobileSessionTabsReconciliation({ ] ) + const { + activateTerminalInventoryRecovery, + isCertifiedTerminalSweepDue, + refreshTerminalInventory, + requestTerminalInventoryRecovery, + resetCertifiedTerminalSweep, + resumePendingTerminalInventoryRecovery, + suspendTerminalInventoryRecovery + } = useMobileTerminalInventoryRecovery({ + client, + connState, + fetchTerminals, + scopeKey: terminalInventoryRecoveryScopeKey + }) + useEffect( () => () => { + suspendTerminalInventoryRecovery(true) controller?.dispose() }, - [controller] + [controller, suspendTerminalInventoryRecovery] ) useEffect(() => { @@ -149,38 +173,57 @@ export function useMobileSessionTabsReconciliation({ useFocusEffect( useCallback(() => { if (!controller || connState !== 'connected') { + suspendTerminalInventoryRecovery(true) return } + activateTerminalInventoryRecovery() + resetCertifiedTerminalSweep() const refresh = (forceTabs: boolean): void => { if (AppState.currentState !== 'active') { + suspendTerminalInventoryRecovery(true) controller.setReconciliationActive(false) return } + activateTerminalInventoryRecovery() controller.setReconciliationActive(true) - if (forceTabs) { - void controller.requestReconciliation() - } else { - void controller.poll() + const tabsRequest = forceTabs ? controller.requestReconciliation() : controller.poll() + const now = Date.now() + // Why: healthy tab streams own liveness; retain only a slow inventory sweep for stale handles and metadata. + if (forceTabs || tabsRequest !== null || isCertifiedTerminalSweepDue(now)) { + void refreshTerminalInventory() } - void fetchTerminals() + resumePendingTerminalInventoryRecovery() } const appStateSubscription = AppState.addEventListener('change', (state) => { if (state === 'active') { + activateTerminalInventoryRecovery() resetPendingTerminalRecovery() refresh(true) } else { + suspendTerminalInventoryRecovery(true) controller.setReconciliationActive(false) } }) - const interval = setInterval(() => refresh(false), 2000) + const interval = setInterval(() => refresh(false), RECONCILIATION_INTERVAL_MS) resetPendingTerminalRecovery() refresh(true) return () => { + suspendTerminalInventoryRecovery(true) controller.setReconciliationActive(false) clearInterval(interval) appStateSubscription.remove() } - }, [connState, controller, fetchTerminals, resetPendingTerminalRecovery]) + }, [ + activateTerminalInventoryRecovery, + connState, + controller, + isCertifiedTerminalSweepDue, + refreshTerminalInventory, + resetPendingTerminalRecovery, + resetCertifiedTerminalSweep, + resumePendingTerminalInventoryRecovery, + suspendTerminalInventoryRecovery + ]) ) return { @@ -199,6 +242,7 @@ export function useMobileSessionTabsReconciliation({ retryPendingTerminalRecovery: useCallback(() => { resetPendingTerminalRecovery() return controller?.retryReconciliation() ?? resolved - }, [controller, resetPendingTerminalRecovery]) + }, [controller, resetPendingTerminalRecovery]), + requestTerminalInventoryRecovery } } diff --git a/mobile/src/session/use-mobile-terminal-inventory-recovery.test.ts b/mobile/src/session/use-mobile-terminal-inventory-recovery.test.ts new file mode 100644 index 00000000000..83d568b4151 --- /dev/null +++ b/mobile/src/session/use-mobile-terminal-inventory-recovery.test.ts @@ -0,0 +1,322 @@ +import { createElement, useEffect } from 'react' +import { act, create, type ReactTestRenderer } from 'react-test-renderer' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { RpcClient } from '../transport/rpc-client' +import { + useMobileTerminalInventoryRecovery, + useMobileTerminalInventoryRecoveryBridge +} from './use-mobile-terminal-inventory-recovery' + +const lifecycle = vi.hoisted(() => ({ appState: 'active' })) + +vi.mock('react-native', () => ({ + AppState: { + get currentState() { + return lifecycle.appState + } + } +})) + +function deferred() { + let resolve!: (value: T) => void + let reject!: (reason?: unknown) => void + const promise = new Promise((resolvePromise, rejectPromise) => { + resolve = resolvePromise + reject = rejectPromise + }) + return { promise, reject, resolve } +} + +const client = { + getState: () => 'connected' +} as unknown as RpcClient +const fetchTerminals = vi.fn(async () => true) +type RecoveryActions = ReturnType +let actions: RecoveryActions | null = null + +function Harness({ scopeKey }: { scopeKey: string }): null { + const recovery = useMobileTerminalInventoryRecovery({ + client, + connState: 'connected', + fetchTerminals, + scopeKey + }) + useEffect(() => { + actions = recovery + return () => { + if (actions === recovery) { + actions = null + } + } + }, [recovery]) + return null +} + +function BridgeHarness({ + scopeKey, + connect, + request +}: { + scopeKey: string + connect: boolean + request: () => void +}): null { + const bridge = useMobileTerminalInventoryRecoveryBridge(scopeKey) + useEffect(() => { + bridgeSignal = bridge.signalTerminalInventoryRecovery + if (!connect) { + return () => { + if (bridgeSignal === bridge.signalTerminalInventoryRecovery) { + bridgeSignal = null + } + } + } + return bridge.registerTerminalInventoryRecoveryAction(request) + }, [bridge, connect, request]) + return null +} + +let bridgeSignal: (() => void) | null = null + +async function flush(): Promise { + await Promise.resolve() + await Promise.resolve() +} + +describe('useMobileTerminalInventoryRecovery', () => { + let renderer: ReactTestRenderer | null = null + let bridgeRenderer: ReactTestRenderer | null = null + + async function mount(scopeKey = 'host::worktree-a'): Promise { + await act(async () => { + renderer = create(createElement(Harness, { scopeKey })) + await flush() + }) + act(() => actions?.activateTerminalInventoryRecovery()) + } + + beforeEach(() => { + vi.useFakeTimers() + lifecycle.appState = 'active' + fetchTerminals.mockReset() + fetchTerminals.mockResolvedValue(true) + bridgeSignal = null + }) + + afterEach(() => { + act(() => renderer?.unmount()) + act(() => bridgeRenderer?.unmount()) + renderer = null + bridgeRenderer = null + actions = null + bridgeSignal = null + vi.useRealTimers() + }) + + it('queues a bridge signal until the recovery action connects', async () => { + const request = vi.fn() + await act(async () => { + bridgeRenderer = create( + createElement(BridgeHarness, { scopeKey: 'scope-a', connect: false, request }) + ) + await flush() + }) + + const preConnectSignal = bridgeSignal + expect(preConnectSignal).toEqual(expect.any(Function)) + act(() => preConnectSignal?.()) + expect(request).not.toHaveBeenCalled() + + await act(async () => { + bridgeRenderer?.update( + createElement(BridgeHarness, { scopeKey: 'scope-a', connect: true, request }) + ) + await flush() + }) + expect(request).toHaveBeenCalledExactlyOnceWith() + }) + + it('ignores a stale bridge signal after the committed scope changes', async () => { + const requestA = vi.fn() + const requestB = vi.fn() + await act(async () => { + bridgeRenderer = create( + createElement(BridgeHarness, { scopeKey: 'scope-a', connect: true, request: requestA }) + ) + await flush() + }) + const staleSignal = bridgeSignal + + await act(async () => { + bridgeRenderer?.update( + createElement(BridgeHarness, { scopeKey: 'scope-b', connect: true, request: requestB }) + ) + await flush() + }) + act(() => staleSignal?.()) + expect(requestA).not.toHaveBeenCalled() + expect(requestB).not.toHaveBeenCalled() + + act(() => bridgeSignal?.()) + expect(requestB).toHaveBeenCalledExactlyOnceWith() + }) + + it('coalesces signals before confirmation into the scheduled pass', async () => { + const firstPass = deferred() + const confirmation = deferred() + fetchTerminals + .mockImplementationOnce(() => firstPass.promise) + .mockImplementationOnce(() => confirmation.promise) + await mount() + + act(() => { + actions?.requestTerminalInventoryRecovery() + actions?.requestTerminalInventoryRecovery() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + await act(async () => { + firstPass.resolve(true) + await flush() + actions?.requestTerminalInventoryRecovery() + await vi.advanceTimersByTimeAsync(750) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + + await act(async () => { + confirmation.resolve(true) + await flush() + await vi.advanceTimersByTimeAsync(10_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + }) + + it.each(['failure', 'rejection'] as const)( + 'retries one queued signal after a first-pass %s', + async (outcome) => { + const firstPass = deferred() + fetchTerminals.mockImplementationOnce(() => firstPass.promise).mockResolvedValueOnce(false) + await mount() + + act(() => { + actions?.requestTerminalInventoryRecovery() + actions?.requestTerminalInventoryRecovery() + }) + await act(async () => { + if (outcome === 'failure') { + firstPass.resolve(false) + } else { + firstPass.reject(new Error('transport lost')) + } + await flush() + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(2) + await act(async () => { + await vi.advanceTimersByTimeAsync(10_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + } + ) + + it('runs one follow-up cycle for signals received during confirmation', async () => { + const confirmation = deferred() + fetchTerminals + .mockResolvedValueOnce(true) + .mockImplementationOnce(() => confirmation.promise) + .mockResolvedValueOnce(false) + await mount() + + act(() => actions?.requestTerminalInventoryRecovery()) + await act(async () => { + await flush() + await vi.advanceTimersByTimeAsync(750) + actions?.requestTerminalInventoryRecovery() + actions?.requestTerminalInventoryRecovery() + confirmation.resolve(false) + await flush() + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(3) + await act(async () => { + await vi.advanceTimersByTimeAsync(10_000) + }) + expect(fetchTerminals).toHaveBeenCalledTimes(3) + }) + + it('retains one cycle across lifecycle suspension and fences the old pass', async () => { + const oldPass = deferred() + fetchTerminals.mockImplementationOnce(() => oldPass.promise).mockResolvedValueOnce(false) + await mount() + + act(() => { + actions?.requestTerminalInventoryRecovery() + actions?.suspendTerminalInventoryRecovery(true) + }) + await act(async () => { + oldPass.resolve(false) + await flush() + }) + expect(fetchTerminals).toHaveBeenCalledTimes(1) + + act(() => { + actions?.activateTerminalInventoryRecovery() + actions?.resumePendingTerminalInventoryRecovery() + }) + await act(flush) + expect(fetchTerminals).toHaveBeenCalledTimes(2) + }) + + it('drops queued work when the recovery scope changes', async () => { + const oldPass = deferred() + fetchTerminals.mockImplementationOnce(() => oldPass.promise) + await mount() + + act(() => { + actions?.requestTerminalInventoryRecovery() + actions?.requestTerminalInventoryRecovery() + }) + await act(async () => { + renderer?.update(createElement(Harness, { scopeKey: 'host::worktree-b' })) + }) + await act(async () => { + oldPass.resolve(false) + await flush() + }) + act(() => { + actions?.activateTerminalInventoryRecovery() + actions?.resumePendingTerminalInventoryRecovery() + }) + + expect(fetchTerminals).toHaveBeenCalledTimes(1) + }) + + it('does not let an old inventory completion move the new scope deadline', async () => { + const oldPass = deferred() + let reportPhysicalStart: ((startedAt: number) => void) | undefined + fetchTerminals.mockImplementationOnce(async (options) => { + reportPhysicalStart = options?.onPhysicalRequestStarted + return oldPass.promise + }) + await mount('scope-a') + vi.setSystemTime(100) + const oldRefresh = actions?.refreshTerminalInventory + expect(oldRefresh).toEqual(expect.any(Function)) + const oldRequest = oldRefresh!() + await flush() + reportPhysicalStart?.(100) + expect(actions?.isCertifiedTerminalSweepDue(100)).toBe(false) + + await act(async () => { + renderer?.update(createElement(Harness, { scopeKey: 'scope-b' })) + await flush() + }) + expect(actions?.isCertifiedTerminalSweepDue(100)).toBe(true) + + reportPhysicalStart?.(100) + oldPass.resolve(true) + await oldRequest + await flush() + expect(actions?.isCertifiedTerminalSweepDue(100)).toBe(true) + }) +}) diff --git a/mobile/src/session/use-mobile-terminal-inventory-recovery.ts b/mobile/src/session/use-mobile-terminal-inventory-recovery.ts new file mode 100644 index 00000000000..fe56d68a819 --- /dev/null +++ b/mobile/src/session/use-mobile-terminal-inventory-recovery.ts @@ -0,0 +1,248 @@ +import { useCallback, useEffect, useRef } from 'react' +import { AppState } from 'react-native' +import type { RpcClient } from '../transport/rpc-client' +import type { ConnectionState } from '../transport/types' + +export type MobileTerminalInventoryRefreshOptions = { + allowEmptyLoaded?: boolean + onPhysicalRequestStarted?: (startedAt: number) => void +} + +type MobileTerminalInventoryRecoveryAction = { + request: () => void + scope: string +} + +/** Bridges terminal stream callbacks to the committed route's recovery action. */ +export function useMobileTerminalInventoryRecoveryBridge(scopeKey: string) { + const committedScopeRef = useRef(null) + const actionRef = useRef(null) + const pendingSignalScopeRef = useRef(null) + + useEffect(() => { + committedScopeRef.current = scopeKey + return () => { + if (committedScopeRef.current === scopeKey) { + committedScopeRef.current = null + } + } + }, [scopeKey]) + + const signalTerminalInventoryRecovery = useCallback(() => { + const committedScope = committedScopeRef.current + if (committedScope !== null && committedScope !== scopeKey) { + return + } + const recoveryAction = actionRef.current + if (recoveryAction?.scope === scopeKey) { + recoveryAction.request() + return + } + pendingSignalScopeRef.current = scopeKey + }, [scopeKey]) + + const registerTerminalInventoryRecoveryAction = useCallback( + (request: () => void): (() => void) => { + const recoveryAction = { request, scope: scopeKey } + actionRef.current = recoveryAction + const pendingScope = pendingSignalScopeRef.current + pendingSignalScopeRef.current = null + if (pendingScope === scopeKey) { + request() + } + return () => { + if (actionRef.current === recoveryAction) { + actionRef.current = null + } + } + }, + [scopeKey] + ) + + return { + registerTerminalInventoryRecoveryAction, + signalTerminalInventoryRecovery + } +} + +type Params = { + client: RpcClient | null + connState: ConnectionState + fetchTerminals: (options?: MobileTerminalInventoryRefreshOptions) => Promise + scopeKey: string +} + +type RecoveryState = { + active: boolean + generation: number + pending: boolean + phase: 'idle' | 'first-pass' | 'confirmation-wait' | 'confirmation-pass' + timer: ReturnType | null +} + +const CERTIFIED_TERMINAL_SWEEP_MS = 60_000 +const TERMINAL_INVENTORY_CONFIRMATION_DELAY_MS = 750 + +export function useMobileTerminalInventoryRecovery({ + client, + connState, + fetchTerminals, + scopeKey +}: Params) { + const stateRef = useRef({ + active: false, + generation: 0, + pending: false, + phase: 'idle', + timer: null + }) + const lastAttemptAtRef = useRef(Number.NEGATIVE_INFINITY) + const refreshTerminalInventory = useCallback( + async (options?: MobileTerminalInventoryRefreshOptions): Promise => { + const logicalStartedAt = Date.now() + const generation = stateRef.current.generation + let physicalStartReported = false + try { + return await fetchTerminals({ + ...options, + onPhysicalRequestStarted: (startedAt) => { + physicalStartReported = true + if (stateRef.current.generation === generation) { + lastAttemptAtRef.current = startedAt + } + } + }) + } finally { + if (!physicalStartReported && stateRef.current.generation === generation) { + lastAttemptAtRef.current = logicalStartedAt + } + } + }, + [fetchTerminals] + ) + const isCertifiedTerminalSweepDue = useCallback((now: number): boolean => { + const elapsed = now - lastAttemptAtRef.current + return elapsed < 0 || elapsed >= CERTIFIED_TERMINAL_SWEEP_MS + }, []) + const resetCertifiedTerminalSweep = useCallback(() => { + lastAttemptAtRef.current = Number.NEGATIVE_INFINITY + }, []) + const canRun = useCallback( + () => + stateRef.current.active && + AppState.currentState === 'active' && + connState === 'connected' && + (client?.getState?.() ?? connState) === 'connected', + [client, connState] + ) + const suspendTerminalInventoryRecovery = useCallback((retainPending: boolean): void => { + const state = stateRef.current + state.active = false + state.generation += 1 + state.pending = retainPending && (state.pending || state.phase !== 'idle') + state.phase = 'idle' + if (state.timer !== null) { + clearTimeout(state.timer) + state.timer = null + } + }, []) + const activateTerminalInventoryRecovery = useCallback(() => { + stateRef.current.active = true + }, []) + const requestTerminalInventoryRecovery = useCallback((): void => { + const state = stateRef.current + if (!canRun()) { + state.pending = true + return + } + if (state.phase === 'first-pass' || state.phase === 'confirmation-pass') { + state.pending = true + return + } + if (state.phase === 'confirmation-wait') { + return + } + + const startCycle = (): void => { + state.pending = false + state.phase = 'first-pass' + const generation = state.generation + const finishPass = (): void => { + state.phase = 'idle' + if (state.pending && canRun()) { + startCycle() + } + } + + void (async () => { + let firstPassSucceeded = false + try { + firstPassSucceeded = await refreshTerminalInventory({ allowEmptyLoaded: true }) + } catch { + // A failed inventory is unverifiable. + } + if (generation !== state.generation) { + return + } + if (!firstPassSucceeded) { + finishPass() + return + } + // The confirmation pass also satisfies signals received during the first pass. + state.pending = false + if (!canRun()) { + state.pending = true + state.phase = 'idle' + return + } + state.phase = 'confirmation-wait' + state.timer = setTimeout(() => { + state.timer = null + if (generation !== state.generation) { + return + } + if (!canRun()) { + state.pending = true + state.phase = 'idle' + return + } + state.phase = 'confirmation-pass' + void refreshTerminalInventory({ allowEmptyLoaded: true }) + .catch(() => { + // A transport failure cannot confirm terminal absence. + }) + .finally(() => { + if (generation === state.generation) { + finishPass() + } + }) + }, TERMINAL_INVENTORY_CONFIRMATION_DELAY_MS) + })() + } + + startCycle() + }, [canRun, refreshTerminalInventory]) + const resumePendingTerminalInventoryRecovery = useCallback(() => { + if (stateRef.current.pending) { + requestTerminalInventoryRecovery() + } + }, [requestTerminalInventoryRecovery]) + + useEffect( + () => () => { + suspendTerminalInventoryRecovery(false) + lastAttemptAtRef.current = Number.NEGATIVE_INFINITY + }, + [scopeKey, suspendTerminalInventoryRecovery] + ) + + return { + activateTerminalInventoryRecovery, + isCertifiedTerminalSweepDue, + refreshTerminalInventory, + requestTerminalInventoryRecovery, + resetCertifiedTerminalSweep, + resumePendingTerminalInventoryRecovery, + suspendTerminalInventoryRecovery + } +} diff --git a/mobile/src/transport/mobile-direct-endpoint-probe.test.ts b/mobile/src/transport/mobile-direct-endpoint-probe.test.ts index 3afa8c08aac..69fe8a2ab8a 100644 --- a/mobile/src/transport/mobile-direct-endpoint-probe.test.ts +++ b/mobile/src/transport/mobile-direct-endpoint-probe.test.ts @@ -4,14 +4,12 @@ import { openAuthenticatedDirectEndpoint } from './mobile-direct-endpoint-probe' import type { ConnectionState, HostProfile, RpcResponse } from './types' class FakeClient implements RpcClient { - readonly sendRequest = vi.fn( - async (): Promise => ({ - id: 'rpc-1', - ok: true, - result: {}, - _meta: { runtimeId: 'runtime-1' } - }) - ) + readonly sendRequest = vi.fn(async (): Promise => ({ + id: 'rpc-1', + ok: true, + result: {}, + _meta: { runtimeId: 'runtime-1' } + })) readonly subscribe = vi.fn(() => () => {}) readonly updateTerminalSubscriptionViewport = vi.fn() readonly notifyForeground = vi.fn() diff --git a/mobile/src/transport/mobile-relay-runtime-failover.test.ts b/mobile/src/transport/mobile-relay-runtime-failover.test.ts index 0187ac251d8..795f2618dfb 100644 --- a/mobile/src/transport/mobile-relay-runtime-failover.test.ts +++ b/mobile/src/transport/mobile-relay-runtime-failover.test.ts @@ -41,14 +41,12 @@ vi.mock('./e2ee', () => ({ })) class FakeSession implements RpcClient { - readonly sendRequest = vi.fn( - async (): Promise => ({ - id: 'rpc-1', - ok: true, - result: {}, - _meta: { runtimeId: 'runtime-1' } - }) - ) + readonly sendRequest = vi.fn(async (): Promise => ({ + id: 'rpc-1', + ok: true, + result: {}, + _meta: { runtimeId: 'runtime-1' } + })) readonly subscribe = vi.fn(() => () => {}) readonly updateTerminalSubscriptionViewport = vi.fn() readonly notifyForeground = vi.fn() diff --git a/mobile/src/worktree/mobile-worktree-activation-source.test.ts b/mobile/src/worktree/mobile-worktree-activation-source.test.ts index 0b06f21f70b..6d6497de67f 100644 --- a/mobile/src/worktree/mobile-worktree-activation-source.test.ts +++ b/mobile/src/worktree/mobile-worktree-activation-source.test.ts @@ -1,7 +1,10 @@ import { readFileSync } from 'node:fs' import { describe, expect, it } from 'vitest' -const source = readFileSync(new URL('../../app/h/[hostId]/index.tsx', import.meta.url), 'utf8') +const source = readFileSync( + new URL('../host-screen/use-host-worktree-actions.ts', import.meta.url), + 'utf8' +) function sliceBetween(startPattern: string, endPattern: string): string { const start = source.indexOf(startPattern) @@ -15,7 +18,7 @@ describe('mobile worktree activation', () => { it('opens mobile sessions without foregrounding other paired clients', () => { const openSession = sliceBetween( 'const openWorktreeSession = useCallback(', - 'const handleSortChange = useCallback' + 'const openFloatingWorkspace = useCallback' ) expect(openSession).toContain("sendRequest('worktree.activate'") diff --git a/package.json b/package.json index 7d0cc956642..a83c74cc9ea 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "sherpa-onnx": "1.12.37", "ssh2": "^1.17.0", "tweetnacl": "^1.0.3", - "ws": "^8.21.0", + "ws": "^8.21.3", "yaml": "^2.8.4", "zod": "~4.4.3" }, @@ -181,14 +181,16 @@ "@sanity/diff-match-patch": "^3.2.0", "@stablyai/playwright-test": "^2.1.14", "@tailwindcss/vite": "^4.2.4", - "@tanstack/react-virtual": "^3.13.24", + "@tanstack/react-virtual": "^3.14.10", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@tiptap/extension-code-block": "^3.22.5", "@tiptap/extension-code-block-lowlight": "^3.22.5", "@tiptap/extension-details": "^3.22.5", "@tiptap/extension-image": "^3.22.5", "@tiptap/extension-link": "^3.22.5", + "@tiptap/extension-list": "^3.22.5", "@tiptap/extension-mathematics": "3.22.5", "@tiptap/extension-placeholder": "^3.22.5", "@tiptap/extension-table": "3.22.4", @@ -220,13 +222,13 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "dompurify": "^3.4.13", - "electron": "^43.1.0", + "electron": "^43.4.1", "electron-builder": "^26.15.3", "electron-builder-squirrel-windows": "^26.15.3", "electron-vite": "^5.0.0", "emoji-picker-react": "^4.19.1", "emojibase-data": "17.0.0", - "happy-dom": "^20.9.0", + "happy-dom": "^20.11.8", "html-to-image": "^1.11.13", "husky": "^9.1.7", "i18next-cli": "1.65.0", @@ -235,18 +237,18 @@ "lowlight": "^3.3.0", "lucide-react": "^0.577.0", "marked": "^17.0.1", - "mermaid": "^11.16.1", + "mermaid": "^11.17.2", "monaco-editor": "^0.55.1", - "oxfmt": "^0.52.0", - "oxlint": "^1.77.0", + "oxfmt": "^0.65.0", + "oxlint": "^1.80.0", "oxlint-plugin-react-doctor": "0.9.1", "oxlint-tsgolint": "7.0.2001", - "pdfjs-dist": "^6.2.108", + "pdfjs-dist": "^6.3.289", "pngjs": "^7.0.0", "radix-ui": "^1.6.2", - "react": "^19.2.7", + "react": "^19.2.8", "react-colorful": "^5.7.0", - "react-dom": "^19.2.7", + "react-dom": "^19.2.8", "react-grab": "^0.1.33", "react-markdown": "^10.1.0", "react-refresh": "^0.18.0", @@ -269,7 +271,7 @@ "typescript-api": "npm:typescript@6.0.3", "unified": "^11.0.5", "vite": "npm:rolldown-vite@7.3.1", - "vitest": "^4.1.5", + "vitest": "^4.1.11", "vscode-oniguruma": "^2.0.1", "vscode-textmate": "^9.3.2", "zustand": "^5.0.14" @@ -296,41 +298,7 @@ "engines": { "node": "24" }, - "packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a", - "pnpm": { - "overrides": { - "monaco-editor>dompurify": "3.4.13" - }, - "supportedArchitectures": { - "os": [ - "current", - "darwin", - "linux", - "win32" - ], - "cpu": [ - "current", - "x64", - "arm64" - ] - }, - "onlyBuiltDependencies": [ - "@parcel/watcher", - "cpu-features", - "esbuild", - "node-pty", - "sherpa-onnx" - ], - "patchedDependencies": { - "node-pty@1.1.0": "config/patches/node-pty@1.1.0.patch", - "@xterm/addon-ligatures@0.11.0-beta.287": "config/patches/@xterm__addon-ligatures@0.11.0-beta.287.patch", - "@xterm/addon-webgl@0.20.0-beta.286": "config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch", - "@xterm/addon-serialize@0.15.0-beta.287": "config/patches/@xterm__addon-serialize@0.15.0-beta.287.patch", - "@xterm/xterm@6.1.0-beta.287": "config/patches/@xterm__xterm@6.1.0-beta.287.patch", - "lint-staged@16.4.0": "config/patches/lint-staged@16.4.0.patch", - "@vscode/windows-process-tree@0.8.0": "config/patches/@vscode__windows-process-tree@0.8.0.patch" - } - }, + "packageManager": "pnpm@12.0.0+sha512.9e2e3dc3911995868dc94b8175c217c27e95408fa03b4a22749778f2b34f773b77cdd3b39ede8171b22fcd53be6a35342e9fac9948a68ef58df6488ce89a7e67", "reactDoctor": { "rules": { "react-doctor/js-combine-iterations": "off" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75b6ec89192..f0f2b278864 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,104 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.0.0 + version: 12.0.0 + +packages: + + '@pnpm/exe.darwin-arm64@12.0.0': + resolution: {integrity: sha512-sqeoPfVMIfQhbwzDrKraXY2ynyuWClFqzvfImzAS/yczEru1m5SGvQ9kgFPDvQzJZ9AetedgJeDZC6qYvH8/tQ==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.0.0': + resolution: {integrity: sha512-Quc3J6c9cGTy+LDgz1cLVgCNOU9IERuyAlDoEj0DCilKqvo50Jx1GV8k74iwn4J9fFSKkm8JrwNvtTDj3uWnUA==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.linux-arm64-musl@12.0.0': + resolution: {integrity: sha512-EVWd3OTmgsMFhXx69b5JxIzoabG9Ma7m4OeTaf0ZKBzMnfYi8u21NDQo92ToMrdYL5dYDDCHsyYIjXzk+d0HhA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.0.0': + resolution: {integrity: sha512-cXHHW8M4rAPsYNkKZO9WVcpLLK55i9EaIsZPfIqUuY2eopd5LqnFyBge54HCh1GC0yCX8ySn0hYIi+4OyAEoDg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.0.0': + resolution: {integrity: sha512-UcXwMdFjly0mpddkGigHKTxe27IMv2fUK4IWW/MHmJ3yMguxXmkwNlEI4aE+G1HO2TLo20uNEUWD4ymLe/DaCQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.0.0': + resolution: {integrity: sha512-6Rsl+zEWMOmus7v7/9J3OE8EMvHyNAfxYmDfmhQG4J0985OuT3G3Ho9NSGHjkBn4aU4bgklWifRhe1HX8dUSyw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.0.0': + resolution: {integrity: sha512-O5F76A4oVFrpDGdFxEszRIThOSBfjHdH5c006gR+7UTCfiXrukr1XfqPungUI1DXcSR5gb9jBsPQqQZOAoOOxw==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.0.0': + resolution: {integrity: sha512-5dKFajIEWJ1ai+KHXFJvskY6vchbunmLwSUV2ywbLymcmJjfY5XJVpgzPCyIoVCMVG0zHorr66+hM8h8b3aRfQ==} + cpu: [x64] + os: [win32] + + pnpm@12.0.0: + resolution: {integrity: sha512-ni49w5EZlYaNyUuBdcIXwn6VQI+gO0oidJd48rNPdzt3zdOznt6BcbIvzVO+ajU0Lp+smUimjvWN9kiM6Jp+Zw==} + engines: {node: '>=18.*'} + hasBin: true + +snapshots: + + '@pnpm/exe.darwin-arm64@12.0.0': + optional: true + + '@pnpm/exe.darwin-x64@12.0.0': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.0.0': + optional: true + + '@pnpm/exe.linux-arm64@12.0.0': + optional: true + + '@pnpm/exe.linux-x64-musl@12.0.0': + optional: true + + '@pnpm/exe.linux-x64@12.0.0': + optional: true + + '@pnpm/exe.win32-arm64@12.0.0': + optional: true + + '@pnpm/exe.win32-x64@12.0.0': + optional: true + + pnpm@12.0.0: + optionalDependencies: + '@pnpm/exe.darwin-arm64': 12.0.0 + '@pnpm/exe.darwin-x64': 12.0.0 + '@pnpm/exe.linux-arm64': 12.0.0 + '@pnpm/exe.linux-arm64-musl': 12.0.0 + '@pnpm/exe.linux-x64': 12.0.0 + '@pnpm/exe.linux-x64-musl': 12.0.0 + '@pnpm/exe.win32-arm64': 12.0.0 + '@pnpm/exe.win32-x64': 12.0.0 + +--- lockfileVersion: '9.0' settings: @@ -8,27 +109,13 @@ overrides: monaco-editor>dompurify: 3.4.13 patchedDependencies: - '@vscode/windows-process-tree@0.8.0': - hash: 946ffb2b1026bcb554d9920681fb00f546c28fc5de6d95a877d198b49bf73988 - path: config/patches/@vscode__windows-process-tree@0.8.0.patch - '@xterm/addon-ligatures@0.11.0-beta.287': - hash: 47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920 - path: config/patches/@xterm__addon-ligatures@0.11.0-beta.287.patch - '@xterm/addon-serialize@0.15.0-beta.287': - hash: af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c - path: config/patches/@xterm__addon-serialize@0.15.0-beta.287.patch - '@xterm/addon-webgl@0.20.0-beta.286': - hash: 118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91 - path: config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch - '@xterm/xterm@6.1.0-beta.287': - hash: 46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7 - path: config/patches/@xterm__xterm@6.1.0-beta.287.patch - lint-staged@16.4.0: - hash: 7333b3837f80a7fbd045964db6d76ba4fc118e49134bdbabb00585b6b7b60673 - path: config/patches/lint-staged@16.4.0.patch - node-pty@1.1.0: - hash: 9a2eedbf2448b8ff1387a8a740ee5e4e968bf8484d7d80e12a3f6a2dc26b0e17 - path: config/patches/node-pty@1.1.0.patch + '@vscode/windows-process-tree@0.8.0': 9217ef36c01ed74127fef5512b0c92089cdbf820fd6c109dd671137eebdc7585 + '@xterm/addon-ligatures@0.11.0-beta.287': 47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920 + '@xterm/addon-serialize@0.15.0-beta.287': af3b156143ed2ee9903b753145b63dd4a2ee72cadd7ef333ab0f4d5d3ebfc32c + '@xterm/addon-webgl@0.20.0-beta.286': 2c301a06ad9caa635d746147dcb2b1c69aa026904f65e1183564f08a0e601b91 + '@xterm/xterm@6.1.0-beta.287': 46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7 + lint-staged@16.4.0: 7333b3837f80a7fbd045964db6d76ba4fc118e49134bdbabb00585b6b7b60673 + node-pty@1.1.0: 9a2eedbf2448b8ff1387a8a740ee5e4e968bf8484d7d80e12a3f6a2dc26b0e17 importers: @@ -36,10 +123,10 @@ importers: dependencies: '@electron-toolkit/preload': specifier: ^3.0.2 - version: 3.0.2(electron@43.1.0) + version: 3.0.2(electron@43.4.1(supports-color@7.2.0)) '@electron-toolkit/utils': specifier: ^4.0.0 - version: 4.0.0(electron@43.1.0) + version: 4.0.0(electron@43.4.1(supports-color@7.2.0)) '@floating-ui/dom': specifier: 1.7.6 version: 1.7.6 @@ -60,7 +147,7 @@ importers: version: 0.27.0 electron-updater: specifier: ^6.8.9 - version: 6.8.9 + version: 6.8.9(supports-color@7.2.0) i18next: specifier: ^26.3.1 version: 26.3.1(typescript@7.0.2) @@ -84,7 +171,7 @@ importers: version: 1.5.4 react-i18next: specifier: ^17.0.8 - version: 17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2) + version: 17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2) serve-sim: specifier: ^0.1.40 version: 0.1.40(typescript@7.0.2) @@ -98,8 +185,8 @@ importers: specifier: ^1.0.3 version: 1.0.3 ws: - specifier: ^8.21.0 - version: 8.21.0 + specifier: ^8.21.3 + version: 8.21.3 yaml: specifier: ^2.8.4 version: 2.8.4 @@ -109,19 +196,19 @@ importers: devDependencies: '@dnd-kit/core': specifier: ^6.3.1 - version: 6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@dnd-kit/sortable': specifier: ^10.0.0 - version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7) + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) '@electron-toolkit/tsconfig': specifier: ^2.0.0 version: 2.0.0(@types/node@25.9.5) '@electron/rebuild': specifier: ^4.2.0 - version: 4.2.0 + version: 4.2.0(supports-color@7.2.0) '@monaco-editor/react': specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@playwright/test': specifier: ^1.59.1 version: 1.59.1 @@ -135,17 +222,20 @@ importers: specifier: ^4.2.4 version: 4.2.4(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) '@tanstack/react-virtual': - specifier: ^3.13.24 - version: 3.13.24(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@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) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) + '@tiptap/extension-code-block': + specifier: ^3.22.5 + version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) '@tiptap/extension-code-block-lowlight': specifier: ^3.22.5 version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/extension-code-block@3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(highlight.js@11.11.1)(lowlight@3.3.0) @@ -158,6 +248,9 @@ importers: '@tiptap/extension-link': specifier: ^3.22.5 version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) + '@tiptap/extension-list': + specifier: ^3.22.5 + version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) '@tiptap/extension-mathematics': specifier: 3.22.5 version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(katex@0.16.45) @@ -190,7 +283,7 @@ importers: version: 3.22.5 '@tiptap/react': specifier: ^3.22.5 - version: 3.22.5(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.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) + version: 3.22.5(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tiptap/starter-kit': specifier: ^3.22.5 version: 3.22.5 @@ -235,7 +328,7 @@ importers: version: 0.13.0-beta.287(@xterm/xterm@6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7)) '@xterm/addon-webgl': specifier: 0.20.0-beta.286 - version: 0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7)) + version: 0.20.0-beta.286(patch_hash=2c301a06ad9caa635d746147dcb2b1c69aa026904f65e1183564f08a0e601b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7)) '@xterm/xterm': specifier: 6.1.0-beta.287 version: 6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7) @@ -247,13 +340,13 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@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) + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) dompurify: specifier: ^3.4.13 version: 3.4.13 electron: - specifier: ^43.1.0 - version: 43.1.0 + specifier: ^43.4.1 + version: 43.4.1(supports-color@7.2.0) electron-builder: specifier: ^26.15.3 version: 26.15.3(electron-builder-squirrel-windows@26.15.3) @@ -265,13 +358,13 @@ importers: version: 5.0.0(@swc/core@1.15.46)(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) emoji-picker-react: specifier: ^4.19.1 - version: 4.19.1(react@19.2.7) + version: 4.19.1(react@19.2.8) emojibase-data: specifier: 17.0.0 version: 17.0.0(emojibase@17.0.0) happy-dom: - specifier: ^20.9.0 - version: 20.9.0 + specifier: ^20.11.8 + version: 20.11.8 html-to-image: specifier: ^1.11.13 version: 1.11.13 @@ -280,7 +373,7 @@ importers: version: 9.1.7 i18next-cli: specifier: 1.65.0 - version: 1.65.0(@types/node@25.9.5)(react-dom@19.2.7(react@19.2.7))(typescript@7.0.2) + version: 1.65.0(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(typescript@7.0.2) katex: specifier: ^0.16.45 version: 0.16.45 @@ -292,22 +385,22 @@ importers: version: 3.3.0 lucide-react: specifier: ^0.577.0 - version: 0.577.0(react@19.2.7) + version: 0.577.0(react@19.2.8) marked: specifier: ^17.0.1 version: 17.0.6 mermaid: - specifier: ^11.16.1 - version: 11.16.1 + specifier: ^11.17.2 + version: 11.17.2 monaco-editor: specifier: ^0.55.1 version: 0.55.1 oxfmt: - specifier: ^0.52.0 - version: 0.52.0 + specifier: ^0.65.0 + version: 0.65.0 oxlint: - specifier: ^1.77.0 - version: 1.77.0(oxlint-tsgolint@7.0.2001) + specifier: ^1.80.0 + version: 1.80.0(oxlint-tsgolint@7.0.2001) oxlint-plugin-react-doctor: specifier: 0.9.1 version: 0.9.1 @@ -315,29 +408,29 @@ importers: specifier: 7.0.2001 version: 7.0.2001 pdfjs-dist: - specifier: ^6.2.108 - version: 6.2.108 + specifier: ^6.3.289 + version: 6.3.289 pngjs: specifier: ^7.0.0 version: 7.0.0 radix-ui: specifier: ^1.6.2 - version: 1.6.2(@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) + version: 1.6.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: - specifier: ^19.2.7 - version: 19.2.7 + specifier: ^19.2.8 + version: 19.2.8 react-colorful: specifier: ^5.7.0 - version: 5.7.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 5.7.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react-dom: - specifier: ^19.2.7 - version: 19.2.7(react@19.2.7) + specifier: ^19.2.8 + version: 19.2.8(react@19.2.8) react-grab: specifier: ^0.1.33 - version: 0.1.34(react@19.2.7) + version: 0.1.34(react@19.2.8) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.17)(react@19.2.7) + version: 10.1.0(@types/react@19.2.17)(react@19.2.8) react-refresh: specifier: ^0.18.0 version: 0.18.0 @@ -361,22 +454,22 @@ importers: version: 4.0.0 remark-frontmatter: specifier: ^5.0.0 - version: 5.0.0 + version: 5.0.0(supports-color@7.2.0) remark-gfm: specifier: ^4.0.1 - version: 4.0.1 + version: 4.0.1(supports-color@7.2.0) remark-math: specifier: ^6.0.0 - version: 6.0.0 + version: 6.0.0(supports-color@7.2.0) remark-parse: specifier: ^11.0.0 - version: 11.0.0 + version: 11.0.0(supports-color@7.2.0) shadcn: specifier: ^4.13.1 version: 4.13.1(typescript@7.0.2) sonner: specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: specifier: ^3.5.0 version: 3.5.0 @@ -399,8 +492,8 @@ importers: specifier: npm:rolldown-vite@7.3.1 version: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4) vitest: - specifier: ^4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) + specifier: ^4.1.11 + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) vscode-oniguruma: specifier: ^2.0.1 version: 2.0.1 @@ -409,11 +502,11 @@ importers: version: 9.3.2 zustand: specifier: ^5.0.14 - version: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)) + version: 5.0.14(@types/react@19.2.17)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8)) optionalDependencies: '@vscode/windows-process-tree': specifier: 0.8.0 - version: 0.8.0(patch_hash=946ffb2b1026bcb554d9920681fb00f546c28fc5de6d95a877d198b49bf73988) + version: 0.8.0(patch_hash=9217ef36c01ed74127fef5512b0c92089cdbf820fd6c109dd671137eebdc7585) sherpa-onnx-darwin-arm64: specifier: 1.12.37 version: 1.12.37 @@ -1058,8 +1151,8 @@ packages: resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} engines: {node: '>= 10.0.0'} - '@mermaid-js/parser@1.2.0': - resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@mermaid-js/parser@1.2.1': + resolution: {integrity: sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw==} '@modelcontextprotocol/sdk@1.30.0': resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} @@ -1351,124 +1444,124 @@ packages: '@oxc-project/types@0.141.0': resolution: {integrity: sha512-S4as7z0j0xQkXcJlyY5ehntwK8/wRkQb9Cyqw+J/N2rkWGQGK0SxD6X6DhQTc7qsxVTBxXbxZtBJh3mr3PtIzQ==} - '@oxfmt/binding-android-arm-eabi@0.52.0': - resolution: {integrity: sha512-17EMSJnQ9g+upVHrAUYDMfH5lvRKQ9Nvg8WtEoH72oDr1VpWz+7/o3tD97U1EToen2YAQ/68JmtDYkQUi20dfQ==} + '@oxfmt/binding-android-arm-eabi@0.65.0': + resolution: {integrity: sha512-M10Gs1SSpTNI6ahGx3M/OlIdUF4hkaP6OgUb+MS79t/Pgflk3r1nW5gPFqsZGUAXg0H1AfANT9AvLdBSTIhZKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.52.0': - resolution: {integrity: sha512-A2G1IdwGEW2lLJkIxcvuirRH1CzSl/e0NX11zTlW1gvxJThfwbI/BEoaKrTNpm7M2FchvIf6guvIQU7d5iz+OQ==} + '@oxfmt/binding-android-arm64@0.65.0': + resolution: {integrity: sha512-6DXH5sftNlaHpWJG50hFMF+Qxtq5D2TmahvcDPxWNcGIf8qrC9Y0YgHYcYZ2hlWzaccKXh/f3GcssH8vtkl4JA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.52.0': - resolution: {integrity: sha512-f9+bLvOYxy7NttCLFTvQ7afmqDOWY4wIP9xdvfj5trQ1qj6f2UFAGwZESlfsMjvJNTyRpXfIlOanCI9FOvoeQA==} + '@oxfmt/binding-darwin-arm64@0.65.0': + resolution: {integrity: sha512-K9m7lr53pcOLETNsC88sWes/GWHUGjZyHx95UhYcSXy0r30haLdeXlSufSenEAtoLaW753WN8/l4M7GYcRt6cg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.52.0': - resolution: {integrity: sha512-YSTB9sJ5nnQd/Q0ddHkgof0ZCHPAnWZT1IW2SJ8omz7CP7KluJhO1fNHrpqdxCtpztJwSs4hY1uAee35wKxxaw==} + '@oxfmt/binding-darwin-x64@0.65.0': + resolution: {integrity: sha512-sTNwIx1gre3MyiHOPLu7IGW4UyMScYL4DTmJT01p4vzB0En+OJUQz6KuH8t0PpsClRSaMuY3b0QmtoPItfO8Lg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.52.0': - resolution: {integrity: sha512-NIrRNTTPCs4UbmVs0bxLSCDlLCtIRMJIXklNKaXa5Oj2/K1UIMBvgE8+uPVo01Io3N9HF0+GAX+aAHjUgZS7vA==} + '@oxfmt/binding-freebsd-x64@0.65.0': + resolution: {integrity: sha512-lYZMVIiIpnjGu5hJb2jxA8NYQ/e0OTGuaiAf4dqlGPNnPmUTu23FZRMltmjro/KkQm1uE4NT4n5yJ2zWmKcpfA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.52.0': - resolution: {integrity: sha512-JXUCde8mn3GpgQouz2PXUokgy/uT1QrRJBL2s983VWcSQp62wTFYiNXgTKdeo1Jgbr0IgUnKKvzIk/YBlj/nVQ==} + '@oxfmt/binding-linux-arm-gnueabihf@0.65.0': + resolution: {integrity: sha512-gIdXFAt/bURnjxuoedDEWdZ0PEWEmdDcm8qdpoFYYvW3QMk/5D4vUaH4mlMeRpeTdST4izUgHVO6RawQ4QulJw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.52.0': - resolution: {integrity: sha512-psbUXaRZ+V8DaXz10Qf7LSHtdtdKAmC8fxXgeU608jjzrmWK4quamZMOpl6sf+dikoFHA85uE93Q0BqxrCdQrQ==} + '@oxfmt/binding-linux-arm-musleabihf@0.65.0': + resolution: {integrity: sha512-jJVyADto7gA2AaX5qAjAexrxx9PJQaKWOe8PICE7yKMbjBRyOHcmj9TtVJ+MZYDUQ3hodU0AcoTj0jFQ1W4C6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.52.0': - resolution: {integrity: sha512-Jw7MgWUU9lcLCcy82updISP3EthTlfvAwR6gWNxPzqly7+fLvOi2gHQE9xXQjpqaVLm/8P+gOzlv9ODuoVlaaw==} + '@oxfmt/binding-linux-arm64-gnu@0.65.0': + resolution: {integrity: sha512-p3RFkB+u7u+8up99b/NEcI1hdpLDiGgJYNwDorB60n7eH+eKposAKuMBxx+NqB3b+sJP4CZmYDh9G7X62tUsKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.52.0': - resolution: {integrity: sha512-wZg6bLjDvh2KibyI3QFUYo8GTXneIFsd0JvehtvJiUmQ8WRPERgxd/VM4ctWb86U5FT1FkqgS8/wZKVB+AZScg==} + '@oxfmt/binding-linux-arm64-musl@0.65.0': + resolution: {integrity: sha512-5Prb0uFzJHr+OUD/qS/TmU526wD+PaHDsm3KoRiUXbMIDpTSErjeQYkK3OQeshAvD/PuLa9WGEi9WPajjdOZJg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.52.0': - resolution: {integrity: sha512-IngE8uxhNvxcMrLjZNDo9xNLY7rEK33AKnaMd2B46he1e/mz2CfcW6If/U1wUjdRZddm1QzQaciqZkuMkdh1FA==} + '@oxfmt/binding-linux-ppc64-gnu@0.65.0': + resolution: {integrity: sha512-S8svxTp81obnF3admN9yd+u2rOYXtyzThLGBTg1PY6TPtGcC09BaaXLQD+TBSMa7yvqhCDZ8DFri+S/yG60qCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.52.0': - resolution: {integrity: sha512-H3+DdFMv/efN3Efmhsv18jDrpiWWqKG7wsfAlQBqAt6z/E2Bx+TwEj2Nowe51CPOWB8/mFBC2dAMSgVFLvvowA==} + '@oxfmt/binding-linux-riscv64-gnu@0.65.0': + resolution: {integrity: sha512-WtXBr75G/h2qOHy8SiGtC1R6aS3jt4mE52v1D8AtwMXIgoOmSNP9lKvbSaTRoL0e5wsMPoi6T72QWDYPu+S+nA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.52.0': - resolution: {integrity: sha512-zji+1kb7lJKohSDjzC1IsS+K/cKRs1hdVf0ZH0VbdbiakmtLvN9twBoXo/k8VdjFax7kfo+DyPxS7vv52br1aw==} + '@oxfmt/binding-linux-riscv64-musl@0.65.0': + resolution: {integrity: sha512-YwSLVvpaz4o/nv/miiPEBJz+eJ+VmbgNIrao6RccK9ce+L5EA8wP+ZD0uFeq6wKOza6zoWv/dR0sj6lip6R3EA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.52.0': - resolution: {integrity: sha512-hcLBYedpCy7ToUvvBidWk7+11Yhg1oAZ4+6hKPic/mQI6NaqXJSXMps5nFlwUuX2ewhtLZZDPg63TI042qGKBg==} + '@oxfmt/binding-linux-s390x-gnu@0.65.0': + resolution: {integrity: sha512-XQTPqgvyrgkKcFq+Tp2eK6JS7sqqJ+nRmy2Fav4j3I+i4dJoPJm7YwEdoeSDX9xkqj9jZ/lWfF3bXUWztIrn6A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.52.0': - resolution: {integrity: sha512-IDO2loXK2OtTOhSPchU9MW25mWL2QCDGdJbjN8MXKZVS80qXe5gMTwQWu/gMJ3juoBHbkuUZNB2N1LHzNT7DoA==} + '@oxfmt/binding-linux-x64-gnu@0.65.0': + resolution: {integrity: sha512-cjZlx6S/VkeCNWCbwZriTnLnZeTcV3DEyeRGSw/2wwLP9viq+C0bJ4bC1k/ZLkFxDcB1lUgSasPkYGP1bdraOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.52.0': - resolution: {integrity: sha512-mAV2Hjn0SatJ+KoAzKUC3eJhdJ8wv+3m1KyuS0dTsbF0c5weq+QrCt/DRZZM+uj/XiKzCDEUKYsBF30e2qkcyw==} + '@oxfmt/binding-linux-x64-musl@0.65.0': + resolution: {integrity: sha512-2azCjxdLtK4zCcIOU1dlXlU0xxfbPi6EjwWx7Ac7teWPidIIDOcIhudup83xNCKYhtqeVd/gaVDOxbUq4syXWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.52.0': - resolution: {integrity: sha512-vd4npaUIwChxp7XzkqmepBWTT9YMcSe/NBApVGPC30/lLyOVaV3dvma1SKo03t8O73BPRAG7EyJzGlN5cJM5hQ==} + '@oxfmt/binding-openharmony-arm64@0.65.0': + resolution: {integrity: sha512-KXQ7xi1e/voP0IQaw6fG6XY4Z5+Llf1XmRSZS1t7pVFCecFJ0iXaboKmVwjFtp5MLlT5iWQrJ2U1C3GJdZ2u+Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.52.0': - resolution: {integrity: sha512-k2sz6gWQdMfh5HPpIS+Bw/0UEV/kaK2xuqJRrWL233sEHx9WLlsmvlPFM4HUNThkYbSN0U0vPW7LVKZWDS8hPQ==} + '@oxfmt/binding-win32-arm64-msvc@0.65.0': + resolution: {integrity: sha512-2FbbjG5jEqLSLKVJwBap84uJfpn5Y5A53KEO0aUNr+zeiRB9nyPUIFMcSbZVMFLitfBytFWRNngozXYjb6Rsbw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.52.0': - resolution: {integrity: sha512-rhke69GTcArodLHpjMTfNnvjTEBryDeZcUCKK/VjXDMtfTULl6QRh0ymX5/hbCUv2WjYm9h/QbW++q2vE15gWQ==} + '@oxfmt/binding-win32-ia32-msvc@0.65.0': + resolution: {integrity: sha512-LJ+ZacAPSjegDOnSLyA1TMWAhdDrsK4el3REdr1oL2UtVBCMhO2II/Sb3cEW6mF2MfLhl8hDNCSvc7KSbgk3LQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.52.0': - resolution: {integrity: sha512-q5xL7oeXkZdEtNZWBdvehJcmt+GRu9l2bK40yJs1jJXlqq+r0Hygb1rTjq+FM2o/2xyt4cufH6KRplHp3Jjsvw==} + '@oxfmt/binding-win32-x64-msvc@0.65.0': + resolution: {integrity: sha512-higu9cWEO6XXFzATD1jf0mCK34rNfN2H9JrJie7QB1IhleVpTh0QlLH9Ip2C1H/Nd5n0v5pvRtC+5R0uE4HpVg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1503,124 +1596,124 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.77.0': - resolution: {integrity: sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==} + '@oxlint/binding-android-arm-eabi@1.80.0': + resolution: {integrity: sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.77.0': - resolution: {integrity: sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==} + '@oxlint/binding-android-arm64@1.80.0': + resolution: {integrity: sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.77.0': - resolution: {integrity: sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==} + '@oxlint/binding-darwin-arm64@1.80.0': + resolution: {integrity: sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.77.0': - resolution: {integrity: sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==} + '@oxlint/binding-darwin-x64@1.80.0': + resolution: {integrity: sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.77.0': - resolution: {integrity: sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==} + '@oxlint/binding-freebsd-x64@1.80.0': + resolution: {integrity: sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.77.0': - resolution: {integrity: sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==} + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': + resolution: {integrity: sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.77.0': - resolution: {integrity: sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==} + '@oxlint/binding-linux-arm-musleabihf@1.80.0': + resolution: {integrity: sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.77.0': - resolution: {integrity: sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==} + '@oxlint/binding-linux-arm64-gnu@1.80.0': + resolution: {integrity: sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.77.0': - resolution: {integrity: sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==} + '@oxlint/binding-linux-arm64-musl@1.80.0': + resolution: {integrity: sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.77.0': - resolution: {integrity: sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==} + '@oxlint/binding-linux-ppc64-gnu@1.80.0': + resolution: {integrity: sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.77.0': - resolution: {integrity: sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==} + '@oxlint/binding-linux-riscv64-gnu@1.80.0': + resolution: {integrity: sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.77.0': - resolution: {integrity: sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==} + '@oxlint/binding-linux-riscv64-musl@1.80.0': + resolution: {integrity: sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.77.0': - resolution: {integrity: sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==} + '@oxlint/binding-linux-s390x-gnu@1.80.0': + resolution: {integrity: sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.77.0': - resolution: {integrity: sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==} + '@oxlint/binding-linux-x64-gnu@1.80.0': + resolution: {integrity: sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.77.0': - resolution: {integrity: sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==} + '@oxlint/binding-linux-x64-musl@1.80.0': + resolution: {integrity: sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.77.0': - resolution: {integrity: sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==} + '@oxlint/binding-openharmony-arm64@1.80.0': + resolution: {integrity: sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.77.0': - resolution: {integrity: sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==} + '@oxlint/binding-win32-arm64-msvc@1.80.0': + resolution: {integrity: sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.77.0': - resolution: {integrity: sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==} + '@oxlint/binding-win32-ia32-msvc@1.80.0': + resolution: {integrity: sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.77.0': - resolution: {integrity: sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==} + '@oxlint/binding-win32-x64-msvc@1.80.0': + resolution: {integrity: sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2748,14 +2841,14 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/react-virtual@3.13.24': - resolution: {integrity: sha512-aIJvz5OSkhNIhZIpYivrxrPTKYsjW9Uzy+sP/mx0S3sev2HyvPb7xmjbYvokzEpfgYHy/HjzJ2zFAETuUfgCpg==} + '@tanstack/react-virtual@3.14.10': + resolution: {integrity: sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/virtual-core@3.14.0': - resolution: {integrity: sha512-JLANqGy/D6k4Ujmh8Tr25lGimuOXNiaVyXaCAZS0W+1390sADdGnyUdSWNIfd49gebtIxGMij4IktRVzrdr12Q==} + '@tanstack/virtual-core@3.17.8': + resolution: {integrity: sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==} '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -3364,11 +3457,11 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@vitest/expect@4.1.5': - resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@4.1.5': - resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3378,20 +3471,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.5': - resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.5': - resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.5': - resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.5': - resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.5': - resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} '@vscode/windows-process-tree@0.8.0': resolution: {integrity: sha512-TI+h2GRwX+igD/YYJMQQVAFcsCNSg7Te2yYxQpKMzwto5RsJ8d2KKgOeur/p/6sAOQwZvopiTDOClyTHEn9MhQ==} @@ -3399,6 +3492,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + '@xterm/addon-fit@0.12.0-beta.287': resolution: {integrity: sha512-2MDj+J4x67bjOS/SuBPxSYEWH38NbX6ENV18RbKVOhfRYCX3yERnuHBOrgH9hYdY8rCtsLQmuVgF6cmvCJiV2w==} peerDependencies: @@ -3605,6 +3699,10 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer-image-size@0.6.4: + resolution: {integrity: sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==} + engines: {node: '>=4.0'} + buildcheck@0.0.7: resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==} engines: {node: '>=10.0.0'} @@ -3887,8 +3985,8 @@ packages: peerDependencies: cytoscape: ^3.2.0 - cytoscape@3.33.3: - resolution: {integrity: sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==} + cytoscape@3.34.2: + resolution: {integrity: sha512-Cm2jaj1X/PBNlzV9yH8zcfGOxO7U+CJ/+mxSBVPSchLaugdp4jtlGx5qaHtPRZ6tgiZ5P+o1XoRfJA+ba6KM3g==} engines: {node: '>=0.10'} d3-array@2.12.1: @@ -4033,8 +4131,8 @@ packages: dagre-d3-es@7.0.14: resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} - dayjs@1.11.20: - resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + dayjs@1.11.23: + resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -4205,8 +4303,8 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@43.1.0: - resolution: {integrity: sha512-DPfxpQLd4NL3BJ8DBxYAfmLUKKesF5Rx9dQx5FyczAP8bhOPScjHE48GArVeXu68LlAainuwkmQTQvdZwpIIAQ==} + electron@43.4.1: + resolution: {integrity: sha512-5b+EuiwkgG5iRcsEL34rimgRpkYp15SsfZOa0pC5kXs0Tb82TH4n95rpQzTZa7yRCbA7tm0WoEbuBL6NaAhAcA==} engines: {node: '>= 22.12.0'} hasBin: true @@ -4406,6 +4504,9 @@ packages: fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fastdom@1.0.12: + resolution: {integrity: sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -4583,8 +4684,8 @@ packages: hachure-fill@0.5.2: resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} - happy-dom@20.9.0: - resolution: {integrity: sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==} + happy-dom@20.11.8: + resolution: {integrity: sha512-TeAoM8pTDKNVcP5z3MptRTb7UH9q126GrjTFOgormgA19tmT30JTiIxb1CVXs7xljpItypUp/yHSPFD4QRHMsQ==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -4964,6 +5065,10 @@ packages: resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} hasBin: true + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -5233,8 +5338,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - mermaid@11.16.1: - resolution: {integrity: sha512-TQsq6u22fAn3rek5VOubrhKPo1g5hwC3FXUN9hiyupTckcYiGuuKGkNQrKYwGJkXUxZdojwRG46gsSCFZMDp4g==} + mermaid@11.17.2: + resolution: {integrity: sha512-V6K3C8EBdEsPFZXSKMJe6ppQOENxuHARr9GvHX4hh47lAbhMRD9qf4oEK7LoaRQxULMa80/qt5gHO73aCleBBg==} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -5544,8 +5649,8 @@ packages: resolution: {integrity: sha512-uFkGGr1KMWd6aWv9UAqooYrN78trw8MWWmoPvgWokfBEUq1+eiIQ+qfj3wokhy0fxtZWZk+0dHoS7/yRTJtd6w==} engines: {node: ^20.19.0 || >=22.12.0} - oxfmt@0.52.0: - resolution: {integrity: sha512-nJlYM35F64zTDMecCNhoHNkf+D/eHv7xcjj9XDSj+bFAVtN93m7v8DQMdHd6nDG6Akf/kEYYHmDUBs2Dz27Sug==} + oxfmt@0.65.0: + resolution: {integrity: sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5565,8 +5670,8 @@ packages: resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==} hasBin: true - oxlint@1.77.0: - resolution: {integrity: sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==} + oxlint@1.80.0: + resolution: {integrity: sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5662,8 +5767,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pdfjs-dist@6.2.108: - resolution: {integrity: sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5TcczzOK6261auRkP/M8OBHs9vFQ==} + pdfjs-dist@6.3.289: + resolution: {integrity: sha512-ZHjSVpDa3D6izMq8/04lvkhkATUmL9px6ChPaXc1k6nU2Mrhlg1/7F0bdUqCwUjw3NsPTfPZsMDUU6ZIcRaeQw==} engines: {node: '>=22.13.0 || >=24'} pe-library@0.4.1: @@ -5879,10 +5984,10 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-dom@19.2.7: - resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} peerDependencies: - react: ^19.2.7 + react: ^19.2.8 react-grab@0.1.34: resolution: {integrity: sha512-jtdOdv0kb90oqL+pMszSh9DOLgVRaX4ZE6XN4GkDEpNNUqveQfZT014+EeJraljpqQfuWKW+96NrrRqUD93D2g==} @@ -5952,8 +6057,8 @@ packages: '@types/react': optional: true - react@19.2.7: - resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} engines: {node: '>=0.10.0'} read-binary-file-arch@1.0.6: @@ -6344,6 +6449,9 @@ packages: strict-event-emitter@0.5.1: resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + strictdom@1.0.1: + resolution: {integrity: sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -6668,20 +6776,20 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vitest@4.1.5: - resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.5 - '@vitest/browser-preview': 4.1.5 - '@vitest/browser-webdriverio': 4.1.5 - '@vitest/coverage-istanbul': 4.1.5 - '@vitest/coverage-v8': 4.1.5 - '@vitest/ui': 4.1.5 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -6791,6 +6899,18 @@ packages: utf-8-validate: optional: true + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + wsl-utils@0.3.1: resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} engines: {node: '>=20'} @@ -6916,7 +7036,7 @@ snapshots: '@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@7.2.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -7089,7 +7209,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@7.2.0) transitivePeerDependencies: - supports-color @@ -7108,29 +7228,29 @@ snapshots: '@croct/json@2.1.0': {} - '@dnd-kit/accessibility@3.1.1(react@19.2.7)': + '@dnd-kit/accessibility@3.1.1(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 tslib: 2.8.1 - '@dnd-kit/core@6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.2.7) - '@dnd-kit/utilities': 3.2.2(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@dnd-kit/accessibility': 3.1.1(react@19.2.8) + '@dnd-kit/utilities': 3.2.2(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) tslib: 2.8.1 - '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)': + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@dnd-kit/utilities': 3.2.2(react@19.2.7) - react: 19.2.7 + '@dnd-kit/core': 6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@dnd-kit/utilities': 3.2.2(react@19.2.8) + react: 19.2.8 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.2.7)': + '@dnd-kit/utilities@3.2.2(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 tslib: 2.8.1 '@dotenvx/dotenvx@1.66.0': @@ -7152,17 +7272,17 @@ snapshots: '@electron-internal/extract-zip@1.0.4': {} - '@electron-toolkit/preload@3.0.2(electron@43.1.0)': + '@electron-toolkit/preload@3.0.2(electron@43.4.1(supports-color@7.2.0))': dependencies: - electron: 43.1.0 + electron: 43.4.1(supports-color@7.2.0) '@electron-toolkit/tsconfig@2.0.0(@types/node@25.9.5)': dependencies: '@types/node': 25.9.5 - '@electron-toolkit/utils@4.0.0(electron@43.1.0)': + '@electron-toolkit/utils@4.0.0(electron@43.4.1(supports-color@7.2.0))': dependencies: - electron: 43.1.0 + electron: 43.4.1(supports-color@7.2.0) '@electron/asar@3.4.1': dependencies: @@ -7176,45 +7296,45 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@3.1.0': + '@electron/get@3.1.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: - supports-color - '@electron/get@5.0.0': + '@electron/get@5.0.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 3.0.0 graceful-fs: 4.2.11 progress: 2.0.3 semver: 7.8.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: undici: 7.29.0 transitivePeerDependencies: - supports-color - '@electron/notarize@2.5.0': + '@electron/notarize@2.5.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: - supports-color - '@electron/osx-sign@1.3.3': + '@electron/osx-sign@1.3.3(supports-color@7.2.0)': dependencies: compare-version: 0.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -7222,22 +7342,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/rebuild@4.2.0': + '@electron/rebuild@4.2.0(supports-color@7.2.0)': dependencies: '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) node-abi: 4.33.0 node-api-version: 0.2.1 node-gyp: 12.3.0 - read-binary-file-arch: 1.0.6 + read-binary-file-arch: 1.0.6(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3': + '@electron/universal@2.0.3(supports-color@7.2.0)': dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) dir-compare: 4.2.0 fs-extra: 11.3.6 minimatch: 9.0.9 @@ -7248,7 +7368,7 @@ snapshots: '@electron/windows-sign@1.2.2': dependencies: cross-dirname: 0.1.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 11.3.6 minimist: 1.2.8 postject: 1.0.0-alpha.6 @@ -7359,11 +7479,11 @@ snapshots: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/dom': 1.7.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) '@floating-ui/utils@0.2.11': {} @@ -7535,16 +7655,16 @@ snapshots: dependencies: cross-spawn: 7.0.6 - '@malept/flatpak-bundler@0.4.0': + '@malept/flatpak-bundler@0.4.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 lodash: 4.18.1 tmp-promise: 3.0.3 transitivePeerDependencies: - supports-color - '@mermaid-js/parser@1.2.0': + '@mermaid-js/parser@1.2.1': dependencies: '@chevrotain/types': 11.1.2 @@ -7574,12 +7694,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@monaco-editor/loader': 1.7.0 monaco-editor: 0.55.1 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) '@mswjs/interceptors@0.41.9': dependencies: @@ -7758,61 +7878,61 @@ snapshots: '@oxc-project/types@0.141.0': {} - '@oxfmt/binding-android-arm-eabi@0.52.0': + '@oxfmt/binding-android-arm-eabi@0.65.0': optional: true - '@oxfmt/binding-android-arm64@0.52.0': + '@oxfmt/binding-android-arm64@0.65.0': optional: true - '@oxfmt/binding-darwin-arm64@0.52.0': + '@oxfmt/binding-darwin-arm64@0.65.0': optional: true - '@oxfmt/binding-darwin-x64@0.52.0': + '@oxfmt/binding-darwin-x64@0.65.0': optional: true - '@oxfmt/binding-freebsd-x64@0.52.0': + '@oxfmt/binding-freebsd-x64@0.65.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.52.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.65.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.52.0': + '@oxfmt/binding-linux-arm-musleabihf@0.65.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.52.0': + '@oxfmt/binding-linux-arm64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.52.0': + '@oxfmt/binding-linux-arm64-musl@0.65.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.52.0': + '@oxfmt/binding-linux-ppc64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.52.0': + '@oxfmt/binding-linux-riscv64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.52.0': + '@oxfmt/binding-linux-riscv64-musl@0.65.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.52.0': + '@oxfmt/binding-linux-s390x-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.52.0': + '@oxfmt/binding-linux-x64-gnu@0.65.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.52.0': + '@oxfmt/binding-linux-x64-musl@0.65.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.52.0': + '@oxfmt/binding-openharmony-arm64@0.65.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.52.0': + '@oxfmt/binding-win32-arm64-msvc@0.65.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.52.0': + '@oxfmt/binding-win32-ia32-msvc@0.65.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.52.0': + '@oxfmt/binding-win32-x64-msvc@0.65.0': optional: true '@oxlint-tsgolint/darwin-arm64@7.0.2001': @@ -7833,61 +7953,61 @@ snapshots: '@oxlint-tsgolint/win32-x64@7.0.2001': optional: true - '@oxlint/binding-android-arm-eabi@1.77.0': + '@oxlint/binding-android-arm-eabi@1.80.0': optional: true - '@oxlint/binding-android-arm64@1.77.0': + '@oxlint/binding-android-arm64@1.80.0': optional: true - '@oxlint/binding-darwin-arm64@1.77.0': + '@oxlint/binding-darwin-arm64@1.80.0': optional: true - '@oxlint/binding-darwin-x64@1.77.0': + '@oxlint/binding-darwin-x64@1.80.0': optional: true - '@oxlint/binding-freebsd-x64@1.77.0': + '@oxlint/binding-freebsd-x64@1.80.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.77.0': + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.77.0': + '@oxlint/binding-linux-arm-musleabihf@1.80.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.77.0': + '@oxlint/binding-linux-arm64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.77.0': + '@oxlint/binding-linux-arm64-musl@1.80.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.77.0': + '@oxlint/binding-linux-ppc64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.77.0': + '@oxlint/binding-linux-riscv64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.77.0': + '@oxlint/binding-linux-riscv64-musl@1.80.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.77.0': + '@oxlint/binding-linux-s390x-gnu@1.80.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.77.0': + '@oxlint/binding-linux-x64-gnu@1.80.0': optional: true - '@oxlint/binding-linux-x64-musl@1.77.0': + '@oxlint/binding-linux-x64-musl@1.80.0': optional: true - '@oxlint/binding-openharmony-arm64@1.77.0': + '@oxlint/binding-openharmony-arm64@1.80.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.77.0': + '@oxlint/binding-win32-arm64-msvc@1.80.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.77.0': + '@oxlint/binding-win32-ia32-msvc@1.80.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.77.0': + '@oxlint/binding-win32-x64-msvc@1.80.0': optional: true '@parcel/watcher-android-arm64@2.5.6': @@ -7986,742 +8106,742 @@ snapshots: '@radix-ui/primitive@1.1.5': {} - '@radix-ui/react-accessible-icon@1.1.11(@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)': + '@radix-ui/react-accessible-icon@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-accordion@1.2.16(@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)': + '@radix-ui/react-accordion@1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collapsible': 1.1.16(@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) - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collapsible': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-alert-dialog@1.1.19(@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)': + '@radix-ui/react-alert-dialog@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.19(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dialog': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-arrow@1.1.11(@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)': + '@radix-ui/react-arrow@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-aspect-ratio@1.1.11(@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)': + '@radix-ui/react-aspect-ratio@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-avatar@1.2.2(@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)': + '@radix-ui/react-avatar@1.2.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-checkbox@1.3.7(@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)': + '@radix-ui/react-checkbox@1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-collapsible@1.1.16(@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)': + '@radix-ui/react-collapsible@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-collection@1.1.12(@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)': + '@radix-ui/react-collection@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-context-menu@2.3.3(@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)': + '@radix-ui/react-context-menu@2.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.20(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-menu': 2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-context@1.2.0(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-context@1.2.0(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dialog@1.1.19(@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)': + '@radix-ui/react-dialog@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.12(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dismissable-layer@1.1.15(@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)': + '@radix-ui/react-dismissable-layer@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-dropdown-menu@2.1.20(@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)': + '@radix-ui/react-dropdown-menu@2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.20(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-menu': 2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-focus-scope@1.1.12(@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)': + '@radix-ui/react-focus-scope@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-form@0.1.12(@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)': + '@radix-ui/react-form@0.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-label': 2.1.11(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-label': 2.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-hover-card@1.1.19(@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)': + '@radix-ui/react-hover-card@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-label@2.1.11(@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)': + '@radix-ui/react-label@2.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-menu@2.1.20(@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)': + '@radix-ui/react-menu@2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.12(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-menubar@1.1.20(@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)': + '@radix-ui/react-menubar@1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.20(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-menu': 2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-navigation-menu@1.2.18(@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)': + '@radix-ui/react-navigation-menu@1.2.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-one-time-password-field@0.1.12(@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)': + '@radix-ui/react-one-time-password-field@0.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-password-toggle-field@0.1.7(@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)': + '@radix-ui/react-password-toggle-field@0.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-popover@1.1.19(@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)': + '@radix-ui/react-popover@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.12(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-popper@1.3.3(@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)': + '@radix-ui/react-popper@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-arrow': 1.1.11(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-arrow': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) '@radix-ui/rect': 1.1.2 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-portal@1.1.13(@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)': + '@radix-ui/react-portal@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-presence@1.1.7(@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)': + '@radix-ui/react-presence@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-primitive@2.1.7(@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)': + '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-progress@1.1.12(@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)': + '@radix-ui/react-progress@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-radio-group@1.4.3(@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)': + '@radix-ui/react-radio-group@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-roving-focus@1.1.15(@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)': + '@radix-ui/react-roving-focus@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-scroll-area@1.2.14(@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)': + '@radix-ui/react-scroll-area@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-select@2.3.3(@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)': + '@radix-ui/react-select@2.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.12(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@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) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-separator@1.1.11(@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)': + '@radix-ui/react-separator@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-slider@1.4.3(@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)': + '@radix-ui/react-slider@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-switch@1.3.3(@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)': + '@radix-ui/react-switch@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-tabs@1.1.17(@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)': + '@radix-ui/react-tabs@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-toast@1.2.19(@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)': + '@radix-ui/react-toast@1.2.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-toggle-group@1.1.15(@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)': + '@radix-ui/react-toggle-group@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-toggle': 1.1.14(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-toggle@1.1.14(@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)': + '@radix-ui/react-toggle@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-toolbar@1.1.15(@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)': + '@radix-ui/react-toolbar@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-separator': 1.1.11(@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) - '@radix-ui/react-toggle-group': 1.1.15(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-separator': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle-group': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-tooltip@1.2.12(@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)': + '@radix-ui/react-tooltip@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-escape-keydown@1.1.3(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-escape-keydown@1.1.3(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-previous@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-previous@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-rect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-rect@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: '@radix-ui/rect': 1.1.2 - react: 19.2.7 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-size@1.1.2(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-size@1.1.2(@types/react@19.2.17)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-visually-hidden@1.2.7(@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)': + '@radix-ui/react-visually-hidden@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) @@ -8954,13 +9074,13 @@ snapshots: tailwindcss: 4.2.4 vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4) - '@tanstack/react-virtual@3.13.24(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@tanstack/react-virtual@3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/virtual-core': 3.14.0 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@tanstack/virtual-core': 3.17.8 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - '@tanstack/virtual-core@3.14.0': {} + '@tanstack/virtual-core@3.17.8': {} '@testing-library/dom@10.4.1': dependencies: @@ -8982,12 +9102,12 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@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)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) @@ -9186,7 +9306,7 @@ snapshots: prosemirror-transform: 1.12.0 prosemirror-view: 1.41.8 - '@tiptap/react@3.22.5(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.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)': + '@tiptap/react@3.22.5(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@tiptap/core': 3.22.5(@tiptap/pm@3.22.5) '@tiptap/pm': 3.22.5 @@ -9194,9 +9314,9 @@ snapshots: '@types/react-dom': 19.2.3(@types/react@19.2.17) '@types/use-sync-external-store': 0.0.6 fast-equals: 5.4.0 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - use-sync-external-store: 1.6.0(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + use-sync-external-store: 1.6.0(react@19.2.8) optionalDependencies: '@tiptap/extension-bubble-menu': 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) '@tiptap/extension-floating-menu': 3.22.5(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) @@ -9575,49 +9695,49 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/expect@4.1.5': + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))': + '@vitest/mocker@4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))': dependencies: - '@vitest/spy': 4.1.5 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.14.3(@types/node@25.9.5)(typescript@7.0.2) vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4) - '@vitest/pretty-format@4.1.5': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.5': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.5 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.5': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.5': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.5': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.5 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vscode/windows-process-tree@0.8.0(patch_hash=946ffb2b1026bcb554d9920681fb00f546c28fc5de6d95a877d198b49bf73988)': + '@vscode/windows-process-tree@0.8.0(patch_hash=9217ef36c01ed74127fef5512b0c92089cdbf820fd6c109dd671137eebdc7585)': dependencies: node-addon-api: 7.1.0 optional: true @@ -9650,7 +9770,7 @@ snapshots: dependencies: '@xterm/xterm': 6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7) - '@xterm/addon-webgl@0.20.0-beta.286(patch_hash=118f649459ba56a51627d46603e2d5d81d837ac9c4dc393f5cc20263d0ac1b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7))': + '@xterm/addon-webgl@0.20.0-beta.286(patch_hash=2c301a06ad9caa635d746147dcb2b1c69aa026904f65e1183564f08a0e601b91)(@xterm/xterm@6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7))': dependencies: '@xterm/xterm': 6.1.0-beta.287(patch_hash=46796c152f3b73e28238f44499eaf5a867a863809bc7b470b159526a41e354f7) @@ -9698,33 +9818,33 @@ snapshots: ansi-styles@6.2.3: {} - app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.2.0 - '@electron/universal': 2.0.3 - '@malept/flatpak-bundler': 0.4.0 + '@electron/get': 3.1.0(supports-color@7.2.0) + '@electron/notarize': 2.5.0(supports-color@7.2.0) + '@electron/osx-sign': 1.3.3(supports-color@7.2.0) + '@electron/rebuild': 4.2.0(supports-color@7.2.0) + '@electron/universal': 2.0.3(supports-color@7.2.0) + '@malept/flatpak-bundler': 0.4.0(supports-color@7.2.0) '@noble/hashes': 2.2.0 '@peculiar/webcrypto': 1.7.1 '@types/fs-extra': 9.0.13 ajv: 8.20.0 asn1js: 3.0.10 async-exit-hook: 2.0.1 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chromium-pickle-js: 0.2.0 ci-info: 4.3.1 - debug: 4.4.3 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + debug: 4.4.3(supports-color@7.2.0) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) - electron-publish: 26.15.3 + electron-publish: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -9796,9 +9916,9 @@ snapshots: dependencies: tweetnacl: 0.14.5 - bippy@0.5.40(react@19.2.7): + bippy@0.5.40(react@19.2.8): dependencies: - react: 19.2.7 + react: 19.2.8 bluebird@3.7.2: {} @@ -9806,7 +9926,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -9846,26 +9966,30 @@ snapshots: buffer-from@1.1.2: {} + buffer-image-size@0.6.4: + dependencies: + '@types/node': 25.9.5 + buildcheck@0.0.7: optional: true - builder-util-runtime@9.7.0: + builder-util-runtime@9.7.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) sax: 1.6.0 transitivePeerDependencies: - supports-color - builder-util@26.15.3: + builder-util@26.15.3(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0 + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 7.0.2(supports-color@7.2.0) + https-proxy-agent: 7.0.6(supports-color@7.2.0) js-yaml: 4.3.1 sanitize-filename: 1.6.4 source-map-support: 0.5.21 @@ -9983,14 +10107,14 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@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): + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.19(@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) - '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dialog': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -10090,17 +10214,17 @@ snapshots: csstype@3.2.3: {} - cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.3): + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.2): dependencies: cose-base: 1.0.3 - cytoscape: 3.33.3 + cytoscape: 3.34.2 - cytoscape-fcose@2.2.0(cytoscape@3.33.3): + cytoscape-fcose@2.2.0(cytoscape@3.34.2): dependencies: cose-base: 2.2.0 - cytoscape: 3.33.3 + cytoscape: 3.34.2 - cytoscape@3.33.3: {} + cytoscape@3.34.2: {} d3-array@2.12.1: dependencies: @@ -10274,11 +10398,13 @@ snapshots: d3: 7.9.0 lodash-es: 4.18.1 - dayjs@1.11.20: {} + dayjs@1.11.23: {} - debug@4.4.3: + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 decamelize@1.2.0: {} @@ -10349,10 +10475,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 js-yaml: 4.3.1 transitivePeerDependencies: @@ -10400,8 +10526,8 @@ snapshots: electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) electron-winstaller: 5.4.0 transitivePeerDependencies: - dmg-builder @@ -10409,12 +10535,12 @@ snapshots: electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 ci-info: 4.4.0 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -10423,12 +10549,12 @@ snapshots: - electron-builder-squirrel-windows - supports-color - electron-publish@26.15.3: + electron-publish@26.15.3(supports-color@7.2.0): dependencies: '@types/fs-extra': 9.0.13 aws4: 1.13.2 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 form-data: 4.0.6 fs-extra: 10.1.0 @@ -10439,9 +10565,9 @@ snapshots: electron-to-chromium@1.5.351: {} - electron-updater@6.8.9: + electron-updater@6.8.9(supports-color@7.2.0): dependencies: - builder-util-runtime: 9.7.0 + builder-util-runtime: 9.7.0(supports-color@7.2.0) fs-extra: 10.1.0 js-yaml: 4.3.1 lazy-val: 1.0.5 @@ -10469,7 +10595,7 @@ snapshots: electron-winstaller@5.4.0: dependencies: '@electron/asar': 3.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 7.0.1 lodash: 4.18.1 temp: 0.9.4 @@ -10478,18 +10604,18 @@ snapshots: transitivePeerDependencies: - supports-color - electron@43.1.0: + electron@43.4.1(supports-color@7.2.0): dependencies: '@electron-internal/extract-zip': 1.0.4 - '@electron/get': 5.0.0 + '@electron/get': 5.0.0(supports-color@7.2.0) '@types/node': 24.12.4 transitivePeerDependencies: - supports-color - emoji-picker-react@4.19.1(react@19.2.7): + emoji-picker-react@4.19.1(react@19.2.8): dependencies: flairup: 1.0.0 - react: 19.2.7 + react: 19.2.8 emoji-regex@10.6.0: {} @@ -10665,7 +10791,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -10716,6 +10842,10 @@ snapshots: dependencies: fast-string-width: 3.0.2 + fastdom@1.0.12: + dependencies: + strictdom: 1.0.1 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -10742,7 +10872,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -10919,11 +11049,12 @@ snapshots: hachure-fill@0.5.2: {} - happy-dom@20.9.0: + happy-dom@20.11.8: dependencies: '@types/node': 25.9.5 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 + buffer-image-size: 0.6.4 entities: 7.0.1 whatwg-mimetype: 3.0.0 ws: 8.21.0 @@ -11102,10 +11233,10 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -11114,10 +11245,10 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -11127,7 +11258,7 @@ snapshots: husky@9.1.7: {} - i18next-cli@1.65.0(@types/node@25.9.5)(react-dom@19.2.7(react@19.2.7))(typescript@7.0.2): + i18next-cli@1.65.0(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(typescript@7.0.2): dependencies: '@croct/json5-parser': 0.2.2 '@swc/core': 1.15.46 @@ -11143,8 +11274,8 @@ snapshots: magic-string: 0.30.21 minimatch: 10.2.5 ora: 9.4.0 - react: 19.2.7 - react-i18next: 17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2) + react: 19.2.8 + react-i18next: 17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2) yaml: 2.9.0 transitivePeerDependencies: - '@swc/helpers' @@ -11338,6 +11469,10 @@ snapshots: dependencies: commander: 8.3.0 + katex@0.16.47: + dependencies: + commander: 8.3.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -11475,9 +11610,9 @@ snapshots: dependencies: yallist: 4.0.0 - lucide-react@0.577.0(react@19.2.7): + lucide-react@0.577.0(react@19.2.8): dependencies: - react: 19.2.7 + react: 19.2.8 lz-string@1.5.0: {} @@ -11507,14 +11642,14 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.3: + mdast-util-from-markdown@2.0.3(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 - micromark: 4.0.2 + micromark: 4.0.2(supports-color@7.2.0) micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 @@ -11524,12 +11659,12 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-frontmatter@2.0.1: + mdast-util-frontmatter@2.0.1(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: @@ -11543,62 +11678,62 @@ snapshots: mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 - mdast-util-gfm-footnote@2.1.0: + mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color - mdast-util-gfm-strikethrough@2.0.0: + mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-table@2.0.0: + mdast-util-gfm-table@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-task-list-item@2.0.0: + mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm@3.1.0: + mdast-util-gfm@3.1.0(supports-color@7.2.0): dependencies: - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) + mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-math@3.0.0: + mdast-util-math@3.0.0(supports-color@7.2.0): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 longest-streak: 3.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 unist-util-remove-position: 5.0.0 transitivePeerDependencies: @@ -11610,7 +11745,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11623,7 +11758,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -11638,7 +11773,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11689,23 +11824,24 @@ snapshots: merge2@1.4.1: {} - mermaid@11.16.1: + mermaid@11.17.2: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.1 - '@mermaid-js/parser': 1.2.0 + '@mermaid-js/parser': 1.2.1 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 - cytoscape: 3.33.3 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.3) - cytoscape-fcose: 2.2.0(cytoscape@3.33.3) + cytoscape: 3.34.2 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.2) + cytoscape-fcose: 2.2.0(cytoscape@3.34.2) d3: 7.9.0 d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 - dayjs: 1.11.20 + dayjs: 1.11.23 dompurify: 3.4.13 es-toolkit: 1.46.1 - katex: 0.16.45 + fastdom: 1.0.12 + katex: 0.16.47 khroma: 2.1.0 marked: 16.4.2 roughjs: 4.6.6 @@ -11899,10 +12035,10 @@ snapshots: micromark-util-types@2.0.2: {} - micromark@4.0.2: + micromark@4.0.2(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -12170,29 +12306,29 @@ snapshots: '@oxc-parser/binding-win32-ia32-msvc': 0.141.0 '@oxc-parser/binding-win32-x64-msvc': 0.141.0 - oxfmt@0.52.0: + oxfmt@0.65.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.52.0 - '@oxfmt/binding-android-arm64': 0.52.0 - '@oxfmt/binding-darwin-arm64': 0.52.0 - '@oxfmt/binding-darwin-x64': 0.52.0 - '@oxfmt/binding-freebsd-x64': 0.52.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.52.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.52.0 - '@oxfmt/binding-linux-arm64-gnu': 0.52.0 - '@oxfmt/binding-linux-arm64-musl': 0.52.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.52.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.52.0 - '@oxfmt/binding-linux-riscv64-musl': 0.52.0 - '@oxfmt/binding-linux-s390x-gnu': 0.52.0 - '@oxfmt/binding-linux-x64-gnu': 0.52.0 - '@oxfmt/binding-linux-x64-musl': 0.52.0 - '@oxfmt/binding-openharmony-arm64': 0.52.0 - '@oxfmt/binding-win32-arm64-msvc': 0.52.0 - '@oxfmt/binding-win32-ia32-msvc': 0.52.0 - '@oxfmt/binding-win32-x64-msvc': 0.52.0 + '@oxfmt/binding-android-arm-eabi': 0.65.0 + '@oxfmt/binding-android-arm64': 0.65.0 + '@oxfmt/binding-darwin-arm64': 0.65.0 + '@oxfmt/binding-darwin-x64': 0.65.0 + '@oxfmt/binding-freebsd-x64': 0.65.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.65.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.65.0 + '@oxfmt/binding-linux-arm64-gnu': 0.65.0 + '@oxfmt/binding-linux-arm64-musl': 0.65.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.65.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.65.0 + '@oxfmt/binding-linux-riscv64-musl': 0.65.0 + '@oxfmt/binding-linux-s390x-gnu': 0.65.0 + '@oxfmt/binding-linux-x64-gnu': 0.65.0 + '@oxfmt/binding-linux-x64-musl': 0.65.0 + '@oxfmt/binding-openharmony-arm64': 0.65.0 + '@oxfmt/binding-win32-arm64-msvc': 0.65.0 + '@oxfmt/binding-win32-ia32-msvc': 0.65.0 + '@oxfmt/binding-win32-x64-msvc': 0.65.0 oxlint-plugin-react-doctor@0.9.1: dependencies: @@ -12210,27 +12346,27 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 7.0.2001 '@oxlint-tsgolint/win32-x64': 7.0.2001 - oxlint@1.77.0(oxlint-tsgolint@7.0.2001): + oxlint@1.80.0(oxlint-tsgolint@7.0.2001): optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.77.0 - '@oxlint/binding-android-arm64': 1.77.0 - '@oxlint/binding-darwin-arm64': 1.77.0 - '@oxlint/binding-darwin-x64': 1.77.0 - '@oxlint/binding-freebsd-x64': 1.77.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.77.0 - '@oxlint/binding-linux-arm-musleabihf': 1.77.0 - '@oxlint/binding-linux-arm64-gnu': 1.77.0 - '@oxlint/binding-linux-arm64-musl': 1.77.0 - '@oxlint/binding-linux-ppc64-gnu': 1.77.0 - '@oxlint/binding-linux-riscv64-gnu': 1.77.0 - '@oxlint/binding-linux-riscv64-musl': 1.77.0 - '@oxlint/binding-linux-s390x-gnu': 1.77.0 - '@oxlint/binding-linux-x64-gnu': 1.77.0 - '@oxlint/binding-linux-x64-musl': 1.77.0 - '@oxlint/binding-openharmony-arm64': 1.77.0 - '@oxlint/binding-win32-arm64-msvc': 1.77.0 - '@oxlint/binding-win32-ia32-msvc': 1.77.0 - '@oxlint/binding-win32-x64-msvc': 1.77.0 + '@oxlint/binding-android-arm-eabi': 1.80.0 + '@oxlint/binding-android-arm64': 1.80.0 + '@oxlint/binding-darwin-arm64': 1.80.0 + '@oxlint/binding-darwin-x64': 1.80.0 + '@oxlint/binding-freebsd-x64': 1.80.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.80.0 + '@oxlint/binding-linux-arm-musleabihf': 1.80.0 + '@oxlint/binding-linux-arm64-gnu': 1.80.0 + '@oxlint/binding-linux-arm64-musl': 1.80.0 + '@oxlint/binding-linux-ppc64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-musl': 1.80.0 + '@oxlint/binding-linux-s390x-gnu': 1.80.0 + '@oxlint/binding-linux-x64-gnu': 1.80.0 + '@oxlint/binding-linux-x64-musl': 1.80.0 + '@oxlint/binding-openharmony-arm64': 1.80.0 + '@oxlint/binding-win32-arm64-msvc': 1.80.0 + '@oxlint/binding-win32-ia32-msvc': 1.80.0 + '@oxlint/binding-win32-x64-msvc': 1.80.0 oxlint-tsgolint: 7.0.2001 p-cancelable@2.1.1: {} @@ -12309,7 +12445,7 @@ snapshots: pathe@2.0.3: {} - pdfjs-dist@6.2.108: + pdfjs-dist@6.3.289: optionalDependencies: '@napi-rs/canvas': 1.0.3 @@ -12524,65 +12660,65 @@ snapshots: quick-lru@5.1.1: {} - radix-ui@1.6.2(@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): + radix-ui@1.6.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@radix-ui/primitive': 1.1.5 - '@radix-ui/react-accessible-icon': 1.1.11(@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) - '@radix-ui/react-accordion': 1.2.16(@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) - '@radix-ui/react-alert-dialog': 1.1.19(@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) - '@radix-ui/react-arrow': 1.1.11(@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) - '@radix-ui/react-aspect-ratio': 1.1.11(@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) - '@radix-ui/react-avatar': 1.2.2(@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) - '@radix-ui/react-checkbox': 1.3.7(@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) - '@radix-ui/react-collapsible': 1.1.16(@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) - '@radix-ui/react-collection': 1.1.12(@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) - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context-menu': 2.3.3(@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) - '@radix-ui/react-dialog': 1.1.19(@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) - '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.15(@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) - '@radix-ui/react-dropdown-menu': 2.1.20(@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) - '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.12(@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) - '@radix-ui/react-form': 0.1.12(@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) - '@radix-ui/react-hover-card': 1.1.19(@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) - '@radix-ui/react-label': 2.1.11(@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) - '@radix-ui/react-menu': 2.1.20(@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) - '@radix-ui/react-menubar': 1.1.20(@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) - '@radix-ui/react-navigation-menu': 1.2.18(@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) - '@radix-ui/react-one-time-password-field': 0.1.12(@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) - '@radix-ui/react-password-toggle-field': 0.1.7(@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) - '@radix-ui/react-popover': 1.1.19(@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) - '@radix-ui/react-popper': 1.3.3(@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) - '@radix-ui/react-portal': 1.1.13(@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) - '@radix-ui/react-presence': 1.1.7(@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) - '@radix-ui/react-primitive': 2.1.7(@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) - '@radix-ui/react-progress': 1.1.12(@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) - '@radix-ui/react-radio-group': 1.4.3(@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) - '@radix-ui/react-roving-focus': 1.1.15(@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) - '@radix-ui/react-scroll-area': 1.2.14(@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) - '@radix-ui/react-select': 2.3.3(@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) - '@radix-ui/react-separator': 1.1.11(@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) - '@radix-ui/react-slider': 1.4.3(@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) - '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-switch': 1.3.3(@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) - '@radix-ui/react-tabs': 1.1.17(@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) - '@radix-ui/react-toast': 1.2.19(@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) - '@radix-ui/react-toggle': 1.1.14(@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) - '@radix-ui/react-toggle-group': 1.1.15(@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) - '@radix-ui/react-toolbar': 1.1.15(@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) - '@radix-ui/react-tooltip': 1.2.12(@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) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-escape-keydown': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@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) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + '@radix-ui/react-accessible-icon': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-accordion': 1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-alert-dialog': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-arrow': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-aspect-ratio': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-avatar': 1.2.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-checkbox': 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collapsible': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context-menu': 2.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dialog': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dropdown-menu': 2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-form': 0.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-hover-card': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-label': 2.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menu': 2.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menubar': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-navigation-menu': 1.2.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-one-time-password-field': 0.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-password-toggle-field': 0.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popover': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-progress': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-radio-group': 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-scroll-area': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-select': 2.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-separator': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slider': 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-switch': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-tabs': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toast': 1.2.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle-group': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toolbar': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-tooltip': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-escape-keydown': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) @@ -12596,37 +12732,37 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-colorful@5.7.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + react-colorful@5.7.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - react-dom@19.2.7(react@19.2.7): + react-dom@19.2.8(react@19.2.8): dependencies: - react: 19.2.7 + react: 19.2.8 scheduler: 0.27.0 - react-grab@0.1.34(react@19.2.7): + react-grab@0.1.34(react@19.2.8): dependencies: '@react-grab/cli': 0.1.34 - bippy: 0.5.40(react@19.2.7) + bippy: 0.5.40(react@19.2.8) optionalDependencies: - react: 19.2.7 + react: 19.2.8 - react-i18next@17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2): + react-i18next@17.0.8(i18next@26.3.1(typescript@7.0.2))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2): dependencies: '@babel/runtime': 7.29.7 html-parse-stringify: 3.0.1 i18next: 26.3.1(typescript@7.0.2) - react: 19.2.7 - use-sync-external-store: 1.6.0(react@19.2.7) + react: 19.2.8 + use-sync-external-store: 1.6.0(react@19.2.8) optionalDependencies: - react-dom: 19.2.7(react@19.2.7) + react-dom: 19.2.8(react@19.2.8) typescript: 7.0.2 react-is@17.0.2: {} - react-markdown@10.1.0(@types/react@19.2.17)(react@19.2.7): + react-markdown@10.1.0(@types/react@19.2.17)(react@19.2.8): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -12635,8 +12771,8 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 - react: 19.2.7 - remark-parse: 11.0.0 + react: 19.2.8 + remark-parse: 11.0.0(supports-color@7.2.0) remark-rehype: 11.1.2 unified: 11.0.5 unist-util-visit: 5.1.0 @@ -12646,38 +12782,38 @@ snapshots: react-refresh@0.18.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7): + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.8): dependencies: - react: 19.2.7 - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.17 - react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.7): + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.8): dependencies: - react: 19.2.7 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.7) - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.8 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.7) - use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.7) + use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.8) optionalDependencies: '@types/react': 19.2.17 - react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7): + react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.8): dependencies: get-nonce: 1.0.1 - react: 19.2.7 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.17 - react@19.2.7: {} + react@19.2.8: {} - read-binary-file-arch@1.0.6: + read-binary-file-arch@1.0.6(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -12749,39 +12885,39 @@ snapshots: mdast-util-newline-to-break: 2.0.0 unified: 11.0.5 - remark-frontmatter@5.0.0: + remark-frontmatter@5.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-frontmatter: 2.0.1 + mdast-util-frontmatter: 2.0.1(supports-color@7.2.0) micromark-extension-frontmatter: 2.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-gfm@4.0.1: + remark-gfm@4.0.1(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 + mdast-util-gfm: 3.1.0(supports-color@7.2.0) micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) remark-stringify: 11.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-math@6.0.0: + remark-math@6.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-math: 3.0.0 + mdast-util-math: 3.0.0(supports-color@7.2.0) micromark-extension-math: 3.1.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-parse@11.0.0: + remark-parse@11.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -12902,7 +13038,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -12945,7 +13081,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -13101,10 +13237,10 @@ snapshots: smol-toml@1.6.1: {} - sonner@2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + sonner@2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) source-map-js@1.2.1: {} @@ -13145,6 +13281,8 @@ snapshots: strict-event-emitter@0.5.1: optional: true + strictdom@1.0.1: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -13207,9 +13345,9 @@ snapshots: stylis@4.4.0: {} - sumchecker@3.0.1: + sumchecker@3.0.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -13438,24 +13576,24 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.7): + use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.8): dependencies: - react: 19.2.7 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.17 - use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.7): + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.8): dependencies: detect-node-es: 1.1.0 - react: 19.2.7 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.17 - use-sync-external-store@1.6.0(react@19.2.7): + use-sync-external-store@1.6.0(react@19.2.8): dependencies: - react: 19.2.7 + react: 19.2.8 utf8-byte-length@1.0.5: {} @@ -13482,15 +13620,15 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)): + vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)): dependencies: - '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) - '@vitest/pretty-format': 4.1.5 - '@vitest/runner': 4.1.5 - '@vitest/snapshot': 4.1.5 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -13507,7 +13645,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.9.5 - happy-dom: 20.9.0 + happy-dom: 20.11.8 transitivePeerDependencies: - msw @@ -13581,6 +13719,8 @@ snapshots: ws@8.21.0: {} + ws@8.21.3: {} + wsl-utils@0.3.1: dependencies: is-wsl: 3.1.1 @@ -13649,10 +13789,10 @@ snapshots: zod@4.4.3: {} - zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)): + zustand@5.0.14(@types/react@19.2.17)(react@19.2.8)(use-sync-external-store@1.6.0(react@19.2.8)): optionalDependencies: '@types/react': 19.2.17 - react: 19.2.7 - use-sync-external-store: 1.6.0(react@19.2.7) + react: 19.2.8 + use-sync-external-store: 1.6.0(react@19.2.8) zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 52304c4dedb..5d2bbaad077 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,3 +3,46 @@ # package graph. Without this file `pnpm -r` auto-discovers mobile/ and its # nested package, and the root's patchedDependencies fail as ERR_PNPM_UNUSED_PATCH. packages: [] + +minimumReleaseAge: 4320 +# 6.3.289 is younger than the 3-day age gate; drop this once it ages. +minimumReleaseAgeExclude: + - pdfjs-dist +shamefullyHoist: true + +supportedArchitectures: + os: + - current + - darwin + - linux + - win32 + cpu: + - current + - x64 + - arm64 + +allowBuilds: + '@parcel/watcher': true + '@swc/core': false + '@vscode/windows-process-tree': false + agent-browser: false + cpu-features: true + electron-winstaller: false + esbuild: true + msw: false + node-pty: true + sherpa-onnx: true + ssh2: false + windows-native-registry: false + +overrides: + monaco-editor>dompurify: 3.4.13 + +patchedDependencies: + node-pty@1.1.0: config/patches/node-pty@1.1.0.patch + '@xterm/addon-ligatures@0.11.0-beta.287': config/patches/@xterm__addon-ligatures@0.11.0-beta.287.patch + '@xterm/addon-webgl@0.20.0-beta.286': config/patches/@xterm__addon-webgl@0.20.0-beta.286.patch + '@xterm/addon-serialize@0.15.0-beta.287': config/patches/@xterm__addon-serialize@0.15.0-beta.287.patch + '@xterm/xterm@6.1.0-beta.287': config/patches/@xterm__xterm@6.1.0-beta.287.patch + lint-staged@16.4.0: config/patches/lint-staged@16.4.0.patch + '@vscode/windows-process-tree@0.8.0': config/patches/@vscode__windows-process-tree@0.8.0.patch diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt index b91f1065f84..54837bf4d65 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt @@ -45,11 +45,14 @@ __orca_omp_should_skip_extension() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -69,7 +72,7 @@ __orca_omp_invoke() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt index bce09f52ff0..3d3403ad099 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt @@ -83,11 +83,14 @@ __orca_deferred_init() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -107,7 +110,7 @@ __orca_deferred_init() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt index ee9cb7975ec..d4bb98997c2 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt @@ -48,11 +48,14 @@ __orca_omp_should_skip_extension() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -72,7 +75,7 @@ __orca_omp_invoke() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt index 222cab93896..ee18600acb1 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt @@ -83,11 +83,14 @@ __orca_deferred_init() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -107,7 +110,7 @@ __orca_deferred_init() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt index 9d90929085d..de9c8f95248 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt @@ -37,11 +37,14 @@ __orca_omp_should_skip_extension() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -61,7 +64,7 @@ __orca_omp_invoke() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt index 335b54c60c3..394bc4a6d10 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt @@ -57,11 +57,14 @@ __orca_deferred_init() { return 1 } __orca_omp_cwd_is_usable() { + local __orca_physical_cwd [[ -x . ]] || return 1 - if [[ -n "${PWD:-}" ]]; then - [[ -d "${PWD}" && "${PWD}" -ef . ]] + if [[ -n "${PWD:-}" && -d "${PWD:-}" ]]; then + [[ "${PWD}" -ef . ]] else - builtin pwd -P >/dev/null 2>&1 + # Why compare the path: shell builtins can print a cached path for a deleted cwd. + __orca_physical_cwd="$(builtin pwd -P 2>/dev/null)" || return 1 + [[ -d "$__orca_physical_cwd" && "$__orca_physical_cwd" -ef . ]] fi } __orca_omp_invoke() { @@ -81,7 +84,7 @@ __orca_deferred_init() { __orca_omp() { local __orca_use_extension=1 __orca_omp_should_skip_extension "${1:-}" && __orca_use_extension=0 - if [[ $__orca_use_extension -eq 1 ]] && ! __orca_omp_cwd_is_usable; then + if ! __orca_omp_cwd_is_usable; then local __orca_logical_cwd="${PWD:-${ORCA_WORKTREE_PATH:-${ORCA_ROOT_PATH:-}}}" # Why: a restored shell can retain the deleted directory inode after its path is recreated. ( diff --git a/src/main/ai-vault/session-scanner.ts b/src/main/ai-vault/session-scanner.ts index b4ef6f06ce7..4b0deb4c68f 100644 --- a/src/main/ai-vault/session-scanner.ts +++ b/src/main/ai-vault/session-scanner.ts @@ -85,23 +85,21 @@ export async function scanAiVaultSessions( const candidates = dedupeCodexRolloutFileAliases( discoveries .flatMap((discovery) => - discovery.files.map( - (file): SessionFileCandidate => ({ - agent: discovery.agent, - file, - codexHome: - discovery.agent === 'codex' - ? codexHomeForSessionsDir( - discovery.rootDir, - options.defaultCodexHomeDir ?? DEFAULT_CODEX_HOME_DIR - ) - : null, - antigravityHistoryPath: - discovery.agent === 'antigravity' - ? antigravityHistoryPathForBrainDir(discovery.rootDir) - : undefined - }) - ) + discovery.files.map((file): SessionFileCandidate => ({ + agent: discovery.agent, + file, + codexHome: + discovery.agent === 'codex' + ? codexHomeForSessionsDir( + discovery.rootDir, + options.defaultCodexHomeDir ?? DEFAULT_CODEX_HOME_DIR + ) + : null, + antigravityHistoryPath: + discovery.agent === 'antigravity' + ? antigravityHistoryPathForBrainDir(discovery.rootDir) + : undefined + })) ) .sort((left, right) => right.file.mtimeMs - left.file.mtimeMs), { @@ -203,9 +201,11 @@ async function scanInScopeSessions(args: { excludedFilePaths: args.alreadyParsedFilePaths, issues: args.issues }) - const candidates = files.map( - (file): SessionFileCandidate => ({ agent: 'claude', file, codexHome: null }) - ) + const candidates = files.map((file): SessionFileCandidate => ({ + agent: 'claude', + file, + codexHome: null + })) if (candidates.length === 0) { return [] } diff --git a/src/main/automations/external-manager-discovery.ts b/src/main/automations/external-manager-discovery.ts new file mode 100644 index 00000000000..9eed6c44a40 --- /dev/null +++ b/src/main/automations/external-manager-discovery.ts @@ -0,0 +1,163 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { homedir } from 'node:os' +import { join } from 'node:path' +import type { + ExternalAutomationManager, + ExternalAutomationProvider +} from '../../shared/automations-types' +import type { SshTarget } from '../../shared/ssh-types' +import { getActiveMultiplexer } from '../ssh/ssh-target-registry' +import { mapHermesJobs, mapOpenClawJobs } from './external-job-mappers' +import { readHermesCronOutputRunsPage } from './hermes-cron-output' +import { isExternalAutomationCommandOnPath } from './external-manager-local-command' +import { externalAutomationRelayErrorMessage } from './external-manager-relay' + +const HERMES_HOME = process.env.HERMES_HOME?.trim() || join(homedir(), '.hermes') +const HERMES_CRON_DIR = join(HERMES_HOME, 'cron') +const HERMES_JOBS_FILE = join(HERMES_CRON_DIR, 'jobs.json') +const OPENCLAW_JOBS_FILE = join(homedir(), '.openclaw', 'cron', 'jobs.json') +const PROVIDER_LABELS: Record = { + hermes: 'Hermes', + openclaw: 'OpenClaw' +} + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) +} + +async function readLocalHermesJobs(): Promise { + if (!existsSync(HERMES_JOBS_FILE)) { + return [] + } + const content = await readFile(HERMES_JOBS_FILE, 'utf-8') + const parsed = JSON.parse(content) as unknown + const jobs = Array.isArray(parsed) + ? parsed + : isRecord(parsed) && Array.isArray(parsed.jobs) + ? parsed.jobs + : [] + return Promise.all( + jobs.map(async (job) => { + if (!isRecord(job)) { + return job + } + const jobId = typeof job.id === 'string' ? job.id : null + if (!jobId) { + return job + } + const runsPage = await readHermesCronOutputRunsPage(jobId, { page: 1, pageSize: 0 }) + return { + ...job, + run_count: runsPage.total, + runs: [] + } + }) + ) +} + +async function readLocalOpenClawJobs(): Promise { + if (!existsSync(OPENCLAW_JOBS_FILE)) { + return [] + } + const content = await readFile(OPENCLAW_JOBS_FILE, 'utf-8') + const parsed = JSON.parse(content) as unknown + return isRecord(parsed) && Array.isArray(parsed.jobs) ? parsed.jobs : [] +} + +function mapProviderJobs( + provider: ExternalAutomationProvider, + managerId: string, + jobs: unknown[] +): ExternalAutomationManager['jobs'] { + return provider === 'hermes' ? mapHermesJobs(managerId, jobs) : mapOpenClawJobs(managerId, jobs) +} + +export async function listLocalManager( + provider: ExternalAutomationProvider +): Promise { + const [availableResult, jobsResult] = await Promise.allSettled([ + isExternalAutomationCommandOnPath(provider), + provider === 'hermes' ? readLocalHermesJobs() : readLocalOpenClawJobs() + ]) + const available = availableResult.status === 'fulfilled' && availableResult.value + const jobs = jobsResult.status === 'fulfilled' ? jobsResult.value : [] + const readError = jobsResult.status === 'rejected' ? String(jobsResult.reason) : null + if (!available && jobs.length === 0 && !readError) { + return null + } + const managerId = `${provider}:local` + const providerLabel = PROVIDER_LABELS[provider] + return { + id: managerId, + provider, + label: `${providerLabel} on this computer`, + targetLabel: 'this computer', + target: { type: 'local' }, + status: readError ? 'unavailable' : 'available', + error: + readError ?? + (available + ? null + : `${providerLabel} jobs were found, but the ${provider} CLI is not on PATH.`), + canManage: !readError && available, + jobs: mapProviderJobs(provider, managerId, jobs) + } +} + +export async function listRemoteManager( + target: SshTarget, + provider: ExternalAutomationProvider +): Promise { + const providerLabel = PROVIDER_LABELS[provider] + const managerProviderId = `${provider}:ssh:${target.id}` + const mux = getActiveMultiplexer(target.id) + if (!mux || mux.isDisposed()) { + return { + id: managerProviderId, + provider, + label: `${providerLabel} on ${target.label}`, + targetLabel: target.label, + target: { type: 'ssh', connectionId: target.id }, + status: 'unavailable', + error: 'SSH target is not connected.', + canManage: false, + jobs: [] + } + } + try { + const result = (await mux.request('externalAutomations.list', { provider })) as { + jobs?: unknown[] + hermesAvailable?: boolean + openclawAvailable?: boolean + error?: string | null + } + const commandAvailable = + provider === 'hermes' ? result.hermesAvailable === true : result.openclawAvailable === true + const readError = result.error ?? null + return { + id: managerProviderId, + provider, + label: `${providerLabel} on ${target.label}`, + targetLabel: target.label, + target: { type: 'ssh', connectionId: target.id }, + status: readError ? 'unavailable' : 'available', + error: + readError ?? (commandAvailable ? null : `${providerLabel} CLI is not on the remote PATH.`), + canManage: !readError && commandAvailable, + jobs: mapProviderJobs(provider, managerProviderId, result.jobs ?? []) + } + } catch (error) { + return { + id: managerProviderId, + provider, + label: `${providerLabel} on ${target.label}`, + targetLabel: target.label, + target: { type: 'ssh', connectionId: target.id }, + status: 'unavailable', + error: externalAutomationRelayErrorMessage(error), + canManage: false, + jobs: [] + } + } +} diff --git a/src/main/automations/external-manager-job-id.ts b/src/main/automations/external-manager-job-id.ts new file mode 100644 index 00000000000..6d8ac157f98 --- /dev/null +++ b/src/main/automations/external-manager-job-id.ts @@ -0,0 +1,7 @@ +const EXTERNAL_JOB_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/ + +export function assertExternalAutomationJobId(jobId: string): void { + if (!EXTERNAL_JOB_ID_PATTERN.test(jobId)) { + throw new Error('Invalid external automation job ID.') + } +} diff --git a/src/main/automations/external-manager-local-command.ts b/src/main/automations/external-manager-local-command.ts new file mode 100644 index 00000000000..44d81e68ec8 --- /dev/null +++ b/src/main/automations/external-manager-local-command.ts @@ -0,0 +1,45 @@ +import { runProcess } from '../../shared/child-process/run-process' + +const LOCAL_COMMAND_LOOKUP_TIMEOUT_MS = 5_000 +const LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS = 30_000 + +function runLocalProviderCommand( + command: string, + args: string[], + options: { timeoutMs: number; timeoutMessage: string } +): Promise { + return runProcess({ program: command, args, timeoutMs: options.timeoutMs }).then((result) => { + if (result.timedOut) { + throw new Error(options.timeoutMessage) + } + if (result.code !== 0) { + throw new Error( + result.stderr.trim() || `Command exited with code ${result.code ?? 'unknown'}.` + ) + } + }) +} + +export async function isExternalAutomationCommandOnPath(command: string): Promise { + const finder = process.platform === 'win32' ? 'where' : 'which' + try { + // Why: these probes run while loading Automations; a wedged PATH shim must + // not keep the list IPC pending forever. + await runLocalProviderCommand(finder, [command], { + timeoutMs: LOCAL_COMMAND_LOOKUP_TIMEOUT_MS, + timeoutMessage: `Command lookup timed out after ${LOCAL_COMMAND_LOOKUP_TIMEOUT_MS}ms.` + }) + return true + } catch { + return false + } +} + +// Why: local automation mutations back UI actions; a wedged CLI must not keep +// create/edit/run/delete pending after Node signals a timeout. +export function runLocalAutomationCommand(command: string, args: string[]): Promise { + return runLocalProviderCommand(command, args, { + timeoutMs: LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS, + timeoutMessage: `Local automation command timed out after ${LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS}ms.` + }) +} diff --git a/src/main/automations/external-manager-mutations.ts b/src/main/automations/external-manager-mutations.ts new file mode 100644 index 00000000000..215e00e7a8e --- /dev/null +++ b/src/main/automations/external-manager-mutations.ts @@ -0,0 +1,139 @@ +import type { + ExternalAutomationAction, + ExternalAutomationActionInput, + ExternalAutomationCreateInput, + ExternalAutomationProvider, + ExternalAutomationUpdateInput +} from '../../shared/automations-types' +import { assertExternalAutomationJobId } from './external-manager-job-id' +import { runLocalAutomationCommand } from './external-manager-local-command' +import { requireExternalAutomationMultiplexer } from './external-manager-relay' +import { clearHermesCronOutputRunCountCache } from './hermes-cron-output' + +const PROVIDER_ACTION_COMMANDS: Record< + ExternalAutomationProvider, + Record +> = { + hermes: { pause: 'pause', resume: 'resume', run: 'run', delete: 'remove' }, + openclaw: { pause: 'disable', resume: 'enable', run: 'run', delete: 'rm' } +} + +/** Fails closed like its neighbours: an unlisted or inherited key is not an action. */ +function providerActionCommand( + provider: ExternalAutomationProvider, + action: ExternalAutomationAction +): string { + const commands = Object.hasOwn(PROVIDER_ACTION_COMMANDS, provider) + ? PROVIDER_ACTION_COMMANDS[provider] + : null + const command = commands && Object.hasOwn(commands, action) ? commands[action] : null + if (typeof command !== 'string') { + throw new Error('Unsupported external automation action.') + } + return command +} + +function normalizeHermesCronMutationInput(input: ExternalAutomationCreateInput): { + name: string + prompt: string + schedule: string + workdir: string | null +} { + if (input.provider !== 'hermes') { + throw new Error('Only Hermes cron creation and editing are supported.') + } + const name = input.name.trim() + const prompt = input.prompt.trim() + const schedule = input.schedule.trim() + const workdir = input.workdir?.trim() || null + if (!prompt) { + throw new Error('Hermes cron requires a prompt.') + } + if (!schedule) { + throw new Error('Hermes cron requires a schedule.') + } + return { + name: name || prompt.slice(0, 50).trim() || 'Hermes cron', + prompt, + schedule, + workdir + } +} + +/** Edit args when `jobId` is given, create args otherwise; both are argv, never a shell string. */ +function hermesCronMutationArgs( + jobId: string | null, + input: { name: string; prompt: string; schedule: string; workdir: string | null } +): string[] { + const args = jobId + ? ['cron', 'edit', jobId, '--schedule', input.schedule, '--prompt', input.prompt] + : ['cron', 'create', input.schedule, input.prompt] + args.push('--name', input.name) + if (!jobId) { + args.push('--deliver', 'local') + } + if (input.workdir) { + args.push('--workdir', input.workdir) + } + return args +} + +export async function createExternalAutomation( + input: ExternalAutomationCreateInput +): Promise { + const normalized = normalizeHermesCronMutationInput(input) + if (input.target.type === 'local') { + await runLocalAutomationCommand('hermes', hermesCronMutationArgs(null, normalized)) + clearHermesCronOutputRunCountCache() + return + } + await requireExternalAutomationMultiplexer(input.target.connectionId).request( + 'externalAutomations.create', + { + provider: input.provider, + ...normalized + } + ) +} + +export async function updateExternalAutomation( + input: ExternalAutomationUpdateInput +): Promise { + assertExternalAutomationJobId(input.jobId) + const normalized = normalizeHermesCronMutationInput(input) + if (input.target.type === 'local') { + await runLocalAutomationCommand('hermes', hermesCronMutationArgs(input.jobId, normalized)) + clearHermesCronOutputRunCountCache(input.jobId) + return + } + await requireExternalAutomationMultiplexer(input.target.connectionId).request( + 'externalAutomations.update', + { + provider: input.provider, + jobId: input.jobId, + ...normalized + } + ) +} + +export async function runExternalAutomationAction( + input: ExternalAutomationActionInput +): Promise { + assertExternalAutomationJobId(input.jobId) + const command = providerActionCommand(input.provider, input.action) + if (input.target.type === 'local') { + await runLocalAutomationCommand(input.provider, ['cron', command, input.jobId]) + if (input.provider === 'hermes') { + clearHermesCronOutputRunCountCache(input.jobId) + } + return + } + await requireExternalAutomationMultiplexer(input.target.connectionId).request( + 'externalAutomations.act', + { + provider: input.provider, + action: input.action, + jobId: input.jobId + } + ) +} diff --git a/src/main/automations/external-manager-relay.ts b/src/main/automations/external-manager-relay.ts new file mode 100644 index 00000000000..f223c55d0b8 --- /dev/null +++ b/src/main/automations/external-manager-relay.ts @@ -0,0 +1,35 @@ +import { JsonRpcErrorCode } from '../ssh/relay-protocol' +import { getActiveMultiplexer } from '../ssh/ssh-target-registry' + +export function requireExternalAutomationMultiplexer( + connectionId: string +): NonNullable> { + const mux = getActiveMultiplexer(connectionId) + if (!mux || mux.isDisposed()) { + throw new Error(`SSH target "${connectionId}" is not connected.`) + } + return mux +} + +/** + * True only for a structured JSON-RPC `-32601`, never for error prose. + * + * A `-32601` object means the peer parsed the request and declined the method, + * so it is positive evidence the connection is healthy. Matching the words + * "method not found" instead would let a genuinely broken relay be reported as + * a missing capability, hiding a dead connection behind a capability notice. + */ +export function isRelayMethodNotFoundError(error: unknown): boolean { + return ( + typeof error === 'object' && + error !== null && + (error as { code?: unknown }).code === JsonRpcErrorCode.MethodNotFound + ) +} + +export function externalAutomationRelayErrorMessage(error: unknown): string { + if (isRelayMethodNotFoundError(error)) { + return 'Remote relay does not support external automation management. Reconnect the SSH target to deploy the latest relay.' + } + return error instanceof Error ? error.message : String(error) +} diff --git a/src/main/automations/external-manager-runs.ts b/src/main/automations/external-manager-runs.ts new file mode 100644 index 00000000000..ebb0b0b6dde --- /dev/null +++ b/src/main/automations/external-manager-runs.ts @@ -0,0 +1,81 @@ +import type { + ExternalAutomationProvider, + ExternalAutomationRunsInput, + ExternalAutomationRunsPage +} from '../../shared/automations-types' +import { + EXTERNAL_AUTOMATION_SCOPE_CODES, + ExternalAutomationScopeError +} from '../../shared/external-automation-scope' +import { mapHermesJobs } from './external-job-mappers' +import { assertExternalAutomationJobId } from './external-manager-job-id' +import { + isRelayMethodNotFoundError, + requireExternalAutomationMultiplexer +} from './external-manager-relay' +import { readHermesCronOutputRunsPage } from './hermes-cron-output' + +/** + * Runs the relay's paged runs call, translating "no such method" into a code the + * renderer can act on. + * + * The structured code exists only here: Electron IPC preserves nothing but the + * message, so a renderer that re-derived this from the host's prose would be + * guessing. Translating at the boundary that can still see the code is what lets + * the caller fall back to job-carried runs without matching free text. + */ +async function requestRemoteExternalRuns( + connectionId: string, + params: { provider: ExternalAutomationProvider; jobId: string; page: number; pageSize: number } +): Promise<{ total?: number; runs?: unknown[] }> { + try { + return (await requireExternalAutomationMultiplexer(connectionId).request( + 'externalAutomations.runs', + params + )) as { + total?: number + runs?: unknown[] + } + } catch (error) { + if (isRelayMethodNotFoundError(error)) { + throw new ExternalAutomationScopeError(EXTERNAL_AUTOMATION_SCOPE_CODES.runsUnsupported) + } + throw error + } +} + +export async function listExternalAutomationRuns( + input: ExternalAutomationRunsInput +): Promise { + assertExternalAutomationJobId(input.jobId) + const page = Number.isFinite(input.page) ? Math.max(1, Math.floor(input.page)) : 1 + const pageSize = Number.isFinite(input.pageSize) + ? Math.min(100, Math.max(1, Math.floor(input.pageSize))) + : 25 + const identity = { + managerId: input.managerId, + provider: input.provider, + target: input.target, + jobId: input.jobId, + page, + pageSize + } + if (input.provider !== 'hermes') { + return { ...identity, total: 0, runs: [] } + } + const result = + input.target.type === 'local' + ? await readHermesCronOutputRunsPage(input.jobId, { page, pageSize }) + : await requestRemoteExternalRuns(input.target.connectionId, { + provider: input.provider, + jobId: input.jobId, + page, + pageSize + }) + return { + ...identity, + total: typeof result.total === 'number' && Number.isFinite(result.total) ? result.total : 0, + runs: + mapHermesJobs(input.managerId, [{ id: input.jobId, runs: result.runs ?? [] }])[0]?.runs ?? [] + } +} diff --git a/src/main/automations/external-manager.ts b/src/main/automations/external-manager.ts index 0905f1943de..d1adeb3e83c 100644 --- a/src/main/automations/external-manager.ts +++ b/src/main/automations/external-manager.ts @@ -1,34 +1,16 @@ -/* eslint-disable max-lines -- Why: external automation discovery, pagination, - * and lifecycle routing share provider/target validation and remote relay fallbacks. */ -import { existsSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { homedir } from 'node:os' -import { join } from 'node:path' -import { runProcess } from '../../shared/child-process/run-process' import type { - ExternalAutomationAction, - ExternalAutomationActionInput, ExternalAutomationCreateInput, - ExternalAutomationManager, - ExternalAutomationProvider, - ExternalAutomationRunsInput, - ExternalAutomationRunsPage, - ExternalAutomationUpdateInput + ExternalAutomationRunsPage } from '../../shared/automations-types' -import { - EXTERNAL_AUTOMATION_SCOPE_CODES, - ExternalAutomationScopeError, - type ScopedExternalAutomationRequest, - type ScopedExternalManagerActionRequest, - type ScopedExternalManagerCreateRequest, - type ScopedExternalManagerListRequest, - type ScopedExternalManagerMutationFields, - type ScopedExternalManagerRunsRequest, - type ScopedExternalManagerUpdateRequest +import type { + ScopedExternalAutomationRequest, + ScopedExternalManagerActionRequest, + ScopedExternalManagerCreateRequest, + ScopedExternalManagerListRequest, + ScopedExternalManagerMutationFields, + ScopedExternalManagerRunsRequest, + ScopedExternalManagerUpdateRequest } from '../../shared/external-automation-scope' -import type { SshTarget } from '../../shared/ssh-types' -import { getActiveMultiplexer } from '../ssh/ssh-target-registry' -import { JsonRpcErrorCode } from '../ssh/relay-protocol' import { resolveExternalAutomationScope, type DesktopSshTargetRegistry, @@ -40,423 +22,19 @@ import { type ExternalAutomationManagerCacheEntry } from './external-automation-manager-cache' import type { ExternalAutomationProbeScheduler } from './external-automation-probe-scheduler' -import { mapHermesJobs, mapOpenClawJobs } from './external-job-mappers' +import { listLocalManager, listRemoteManager } from './external-manager-discovery' import { - clearHermesCronOutputRunCountCache, - readHermesCronOutputRunsPage -} from './hermes-cron-output' + createExternalAutomation, + runExternalAutomationAction, + updateExternalAutomation +} from './external-manager-mutations' +import { listExternalAutomationRuns } from './external-manager-runs' -const HERMES_HOME = process.env.HERMES_HOME?.trim() || join(homedir(), '.hermes') -const HERMES_CRON_DIR = join(HERMES_HOME, 'cron') -const HERMES_JOBS_FILE = join(HERMES_CRON_DIR, 'jobs.json') -const OPENCLAW_JOBS_FILE = join(homedir(), '.openclaw', 'cron', 'jobs.json') -const EXTERNAL_JOB_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/ -const LOCAL_COMMAND_LOOKUP_TIMEOUT_MS = 5_000 -const LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS = 30_000 -const PROVIDER_LABELS: Record = { - hermes: 'Hermes', - openclaw: 'OpenClaw' -} - -function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value) -} - -function runLocalProviderCommand( - command: string, - args: string[], - options: { timeoutMs: number; timeoutMessage: string } -): Promise { - return runProcess({ program: command, args, timeoutMs: options.timeoutMs }).then((result) => { - if (result.timedOut) { - throw new Error(options.timeoutMessage) - } - if (result.code !== 0) { - throw new Error( - result.stderr.trim() || `Command exited with code ${result.code ?? 'unknown'}.` - ) - } - }) -} - -async function isCommandOnPath(command: string): Promise { - const finder = process.platform === 'win32' ? 'where' : 'which' - try { - // Why: these probes run while loading Automations; a wedged PATH shim must - // not keep the list IPC pending forever. - await runLocalProviderCommand(finder, [command], { - timeoutMs: LOCAL_COMMAND_LOOKUP_TIMEOUT_MS, - timeoutMessage: `Command lookup timed out after ${LOCAL_COMMAND_LOOKUP_TIMEOUT_MS}ms.` - }) - return true - } catch { - return false - } -} - -// Why: local automation mutations back UI actions; a wedged CLI must not keep -// create/edit/run/delete pending after Node signals a timeout. -function runLocalAutomationCommand(command: string, args: string[]): Promise { - return runLocalProviderCommand(command, args, { - timeoutMs: LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS, - timeoutMessage: `Local automation command timed out after ${LOCAL_AUTOMATION_COMMAND_TIMEOUT_MS}ms.` - }) -} - -async function readLocalHermesJobs(): Promise { - if (!existsSync(HERMES_JOBS_FILE)) { - return [] - } - const content = await readFile(HERMES_JOBS_FILE, 'utf-8') - const parsed = JSON.parse(content) as unknown - const jobs = Array.isArray(parsed) - ? parsed - : isRecord(parsed) && Array.isArray(parsed.jobs) - ? parsed.jobs - : [] - return Promise.all( - jobs.map(async (job) => { - if (!isRecord(job)) { - return job - } - const jobId = typeof job.id === 'string' ? job.id : null - if (!jobId) { - return job - } - const runsPage = await readHermesCronOutputRunsPage(jobId, { page: 1, pageSize: 0 }) - return { - ...job, - run_count: runsPage.total, - runs: [] - } - }) - ) -} - -async function readLocalOpenClawJobs(): Promise { - if (!existsSync(OPENCLAW_JOBS_FILE)) { - return [] - } - const content = await readFile(OPENCLAW_JOBS_FILE, 'utf-8') - const parsed = JSON.parse(content) as unknown - return isRecord(parsed) && Array.isArray(parsed.jobs) ? parsed.jobs : [] -} - -function mapProviderJobs( - provider: ExternalAutomationProvider, - managerId: string, - jobs: unknown[] -): ExternalAutomationManager['jobs'] { - return provider === 'hermes' ? mapHermesJobs(managerId, jobs) : mapOpenClawJobs(managerId, jobs) -} - -async function listLocalManager( - provider: ExternalAutomationProvider -): Promise { - const [availableResult, jobsResult] = await Promise.allSettled([ - isCommandOnPath(provider), - provider === 'hermes' ? readLocalHermesJobs() : readLocalOpenClawJobs() - ]) - const available = availableResult.status === 'fulfilled' && availableResult.value - const jobs = jobsResult.status === 'fulfilled' ? jobsResult.value : [] - const readError = jobsResult.status === 'rejected' ? String(jobsResult.reason) : null - if (!available && jobs.length === 0 && !readError) { - return null - } - const managerId = `${provider}:local` - const providerLabel = PROVIDER_LABELS[provider] - return { - id: managerId, - provider, - label: `${providerLabel} on this computer`, - targetLabel: 'this computer', - target: { type: 'local' }, - status: readError ? 'unavailable' : 'available', - error: - readError ?? - (available - ? null - : `${providerLabel} jobs were found, but the ${provider} CLI is not on PATH.`), - canManage: !readError && available, - jobs: mapProviderJobs(provider, managerId, jobs) - } -} - -function requireMultiplexer( - connectionId: string -): NonNullable> { - const mux = getActiveMultiplexer(connectionId) - if (!mux || mux.isDisposed()) { - throw new Error(`SSH target "${connectionId}" is not connected.`) - } - return mux -} - -/** - * True only for a structured JSON-RPC `-32601`, never for error prose. - * - * A `-32601` object means the peer parsed the request and declined the method, - * so it is positive evidence the connection is healthy. Matching the words - * "method not found" instead would let a genuinely broken relay be reported as - * a missing capability, hiding a dead connection behind a capability notice. - */ -function isRelayMethodNotFoundError(error: unknown): boolean { - return ( - typeof error === 'object' && - error !== null && - (error as { code?: unknown }).code === JsonRpcErrorCode.MethodNotFound - ) -} - -function remoteRelayErrorMessage(error: unknown): string { - if (isRelayMethodNotFoundError(error)) { - return 'Remote relay does not support external automation management. Reconnect the SSH target to deploy the latest relay.' - } - return error instanceof Error ? error.message : String(error) -} - -async function listRemoteManager( - target: SshTarget, - provider: ExternalAutomationProvider -): Promise { - const providerLabel = PROVIDER_LABELS[provider] - const managerProviderId = `${provider}:ssh:${target.id}` - const mux = getActiveMultiplexer(target.id) - if (!mux || mux.isDisposed()) { - return { - id: managerProviderId, - provider, - label: `${providerLabel} on ${target.label}`, - targetLabel: target.label, - target: { type: 'ssh', connectionId: target.id }, - status: 'unavailable', - error: 'SSH target is not connected.', - canManage: false, - jobs: [] - } - } - try { - const result = (await mux.request('externalAutomations.list', { provider })) as { - jobs?: unknown[] - hermesAvailable?: boolean - openclawAvailable?: boolean - error?: string | null - } - const commandAvailable = - provider === 'hermes' ? result.hermesAvailable === true : result.openclawAvailable === true - const readError = result.error ?? null - return { - id: managerProviderId, - provider, - label: `${providerLabel} on ${target.label}`, - targetLabel: target.label, - target: { type: 'ssh', connectionId: target.id }, - status: readError ? 'unavailable' : 'available', - error: - readError ?? (commandAvailable ? null : `${providerLabel} CLI is not on the remote PATH.`), - canManage: !readError && commandAvailable, - jobs: mapProviderJobs(provider, managerProviderId, result.jobs ?? []) - } - } catch (error) { - return { - id: managerProviderId, - provider, - label: `${providerLabel} on ${target.label}`, - targetLabel: target.label, - target: { type: 'ssh', connectionId: target.id }, - status: 'unavailable', - error: remoteRelayErrorMessage(error), - canManage: false, - jobs: [] - } - } -} - -/** - * Runs the relay's paged runs call, translating "no such method" into a code the - * renderer can act on. - * - * The structured code exists only here: Electron IPC preserves nothing but the - * message, so a renderer that re-derived this from the host's prose would be - * guessing. Translating at the boundary that can still see the code is what lets - * the caller fall back to job-carried runs without matching free text. - */ -async function requestRemoteExternalRuns( - connectionId: string, - params: { provider: ExternalAutomationProvider; jobId: string; page: number; pageSize: number } -): Promise<{ total?: number; runs?: unknown[] }> { - try { - return (await requireMultiplexer(connectionId).request('externalAutomations.runs', params)) as { - total?: number - runs?: unknown[] - } - } catch (error) { - if (isRelayMethodNotFoundError(error)) { - throw new ExternalAutomationScopeError(EXTERNAL_AUTOMATION_SCOPE_CODES.runsUnsupported) - } - throw error - } -} - -export async function listExternalAutomationRuns( - input: ExternalAutomationRunsInput -): Promise { - if (!EXTERNAL_JOB_ID_PATTERN.test(input.jobId)) { - throw new Error('Invalid external automation job ID.') - } - const page = Number.isFinite(input.page) ? Math.max(1, Math.floor(input.page)) : 1 - const pageSize = Number.isFinite(input.pageSize) - ? Math.min(100, Math.max(1, Math.floor(input.pageSize))) - : 25 - const identity = { - managerId: input.managerId, - provider: input.provider, - target: input.target, - jobId: input.jobId, - page, - pageSize - } - if (input.provider !== 'hermes') { - return { ...identity, total: 0, runs: [] } - } - const result = - input.target.type === 'local' - ? await readHermesCronOutputRunsPage(input.jobId, { page, pageSize }) - : await requestRemoteExternalRuns(input.target.connectionId, { - provider: input.provider, - jobId: input.jobId, - page, - pageSize - }) - return { - ...identity, - total: typeof result.total === 'number' && Number.isFinite(result.total) ? result.total : 0, - runs: - mapHermesJobs(input.managerId, [{ id: input.jobId, runs: result.runs ?? [] }])[0]?.runs ?? [] - } -} - -const PROVIDER_ACTION_COMMANDS: Record< - ExternalAutomationProvider, - Record -> = { - hermes: { pause: 'pause', resume: 'resume', run: 'run', delete: 'remove' }, - openclaw: { pause: 'disable', resume: 'enable', run: 'run', delete: 'rm' } -} - -/** Fails closed like its neighbours: an unlisted or inherited key is not an action. */ -function providerActionCommand( - provider: ExternalAutomationProvider, - action: ExternalAutomationAction -): string { - const commands = Object.hasOwn(PROVIDER_ACTION_COMMANDS, provider) - ? PROVIDER_ACTION_COMMANDS[provider] - : null - const command = commands && Object.hasOwn(commands, action) ? commands[action] : null - if (typeof command !== 'string') { - throw new Error('Unsupported external automation action.') - } - return command -} - -function normalizeHermesCronMutationInput(input: ExternalAutomationCreateInput): { - name: string - prompt: string - schedule: string - workdir: string | null -} { - if (input.provider !== 'hermes') { - throw new Error('Only Hermes cron creation and editing are supported.') - } - const name = input.name.trim() - const prompt = input.prompt.trim() - const schedule = input.schedule.trim() - const workdir = input.workdir?.trim() || null - if (!prompt) { - throw new Error('Hermes cron requires a prompt.') - } - if (!schedule) { - throw new Error('Hermes cron requires a schedule.') - } - return { - name: name || prompt.slice(0, 50).trim() || 'Hermes cron', - prompt, - schedule, - workdir - } -} - -/** Edit args when `jobId` is given, create args otherwise; both are argv, never a shell string. */ -function hermesCronMutationArgs( - jobId: string | null, - input: { name: string; prompt: string; schedule: string; workdir: string | null } -): string[] { - const args = jobId - ? ['cron', 'edit', jobId, '--schedule', input.schedule, '--prompt', input.prompt] - : ['cron', 'create', input.schedule, input.prompt] - args.push('--name', input.name) - if (!jobId) { - args.push('--deliver', 'local') - } - if (input.workdir) { - args.push('--workdir', input.workdir) - } - return args -} - -export async function createExternalAutomation( - input: ExternalAutomationCreateInput -): Promise { - const normalized = normalizeHermesCronMutationInput(input) - if (input.target.type === 'local') { - await runLocalAutomationCommand('hermes', hermesCronMutationArgs(null, normalized)) - clearHermesCronOutputRunCountCache() - return - } - await requireMultiplexer(input.target.connectionId).request('externalAutomations.create', { - provider: input.provider, - ...normalized - }) -} - -export async function updateExternalAutomation( - input: ExternalAutomationUpdateInput -): Promise { - if (!EXTERNAL_JOB_ID_PATTERN.test(input.jobId)) { - throw new Error('Invalid external automation job ID.') - } - const normalized = normalizeHermesCronMutationInput(input) - if (input.target.type === 'local') { - await runLocalAutomationCommand('hermes', hermesCronMutationArgs(input.jobId, normalized)) - clearHermesCronOutputRunCountCache(input.jobId) - return - } - await requireMultiplexer(input.target.connectionId).request('externalAutomations.update', { - provider: input.provider, - jobId: input.jobId, - ...normalized - }) -} - -export async function runExternalAutomationAction( - input: ExternalAutomationActionInput -): Promise { - if (!EXTERNAL_JOB_ID_PATTERN.test(input.jobId)) { - throw new Error('Invalid external automation job ID.') - } - const command = providerActionCommand(input.provider, input.action) - if (input.target.type === 'local') { - await runLocalAutomationCommand(input.provider, ['cron', command, input.jobId]) - if (input.provider === 'hermes') { - clearHermesCronOutputRunCountCache(input.jobId) - } - return - } - await requireMultiplexer(input.target.connectionId).request('externalAutomations.act', { - provider: input.provider, - action: input.action, - jobId: input.jobId - }) +export { + createExternalAutomation, + listExternalAutomationRuns, + runExternalAutomationAction, + updateExternalAutomation } export type ScopedExternalAutomationDeps = { diff --git a/src/main/browser/browser-guest-shortcut-dispatch.ts b/src/main/browser/browser-guest-shortcut-dispatch.ts index fa4bd966994..5d24dce43ea 100644 --- a/src/main/browser/browser-guest-shortcut-dispatch.ts +++ b/src/main/browser/browser-guest-shortcut-dispatch.ts @@ -160,7 +160,9 @@ export function forwardGuestShortcutInput( if (isFloatingGuest) { renderer.send('ui:closeFloatingItem', { sourceId: browserTabId }) } else { - renderer.send('ui:closeActiveTab') + // Why: carry the guest's page id — activeTabType/activeBrowserTabId can be stale in split + // layouts (guest focus doesn't reach the group's focus-capture), silently dropping the close. + renderer.send('ui:closeActiveTab', { sourceId: browserTabId }) } } else if (keybindingMatchesAction('tab.nextSameType', input, process.platform, keybindings)) { renderer.send('ui:switchTab', 1) diff --git a/src/main/browser/browser-guest-shortcut-forwarding.test.ts b/src/main/browser/browser-guest-shortcut-forwarding.test.ts index 19bf03bd2f8..f7f35917fa9 100644 --- a/src/main/browser/browser-guest-shortcut-forwarding.test.ts +++ b/src/main/browser/browser-guest-shortcut-forwarding.test.ts @@ -872,7 +872,9 @@ describe('setupGuestShortcutForwarding', () => { expect(rendererSendMock).toHaveBeenCalledWith('ui:closeFloatingItem', { sourceId: browserTabId }) - expect(rendererSendMock).not.toHaveBeenCalledWith('ui:closeActiveTab') + expect(rendererSendMock.mock.calls.some(([channel]) => channel === 'ui:closeActiveTab')).toBe( + false + ) }) it('routes workspace/tab index chords to ui:selectFloatingIndex for a floating guest', () => { @@ -903,7 +905,7 @@ describe('setupGuestShortcutForwarding', () => { triggerBeforeInput(closeInput) triggerBeforeInput(workspaceIndexInput) - expect(rendererSendMock).toHaveBeenCalledWith('ui:closeActiveTab') + expect(rendererSendMock).toHaveBeenCalledWith('ui:closeActiveTab', { sourceId: browserTabId }) expect(rendererSendMock).toHaveBeenCalledWith('ui:jumpToWorktreeIndex', 0) expect(rendererSendMock).not.toHaveBeenCalledWith('ui:closeFloatingItem', expect.anything()) expect(rendererSendMock).not.toHaveBeenCalledWith('ui:selectFloatingIndex', expect.anything()) @@ -918,7 +920,7 @@ describe('setupGuestShortcutForwarding', () => { triggerBeforeInput(closeInput) - expect(rendererSendMock).toHaveBeenCalledWith('ui:closeActiveTab') + expect(rendererSendMock).toHaveBeenCalledWith('ui:closeActiveTab', { sourceId: browserTabId }) expect(rendererSendMock).not.toHaveBeenCalledWith('ui:closeFloatingItem', expect.anything()) }) diff --git a/src/main/browser/browser-manager-guest-shortcuts.test.ts b/src/main/browser/browser-manager-guest-shortcuts.test.ts index cc9af9b6329..fa84fd99d50 100644 --- a/src/main/browser/browser-manager-guest-shortcuts.test.ts +++ b/src/main/browser/browser-manager-guest-shortcuts.test.ts @@ -297,7 +297,9 @@ describe('browserManager', () => { expect(rendererSendMock).toHaveBeenNthCalledWith(1, 'ui:newBrowserTab') expect(rendererSendMock).toHaveBeenNthCalledWith(2, 'ui:newTerminalTab') - expect(rendererSendMock).toHaveBeenNthCalledWith(3, 'ui:closeActiveTab') + expect(rendererSendMock).toHaveBeenNthCalledWith(3, 'ui:closeActiveTab', { + sourceId: 'browser-1' + }) expect(rendererSendMock).toHaveBeenNthCalledWith(4, 'ui:switchTabAcrossAllTypes', 1) expect(rendererSendMock).toHaveBeenNthCalledWith(5, 'ui:switchTab', 1) expect(rendererSendMock).toHaveBeenNthCalledWith(6, 'ui:switchTerminalTab', 1) diff --git a/src/main/browser/cdp-bridge-command-module.ts b/src/main/browser/cdp-bridge-command-module.ts new file mode 100644 index 00000000000..b6cbbb424c3 --- /dev/null +++ b/src/main/browser/cdp-bridge-command-module.ts @@ -0,0 +1,132 @@ +import type { WebContents } from 'electron' +import type { BrowserScreenshotResult, BrowserScrollResult } from '../../shared/runtime-types' +import type { CdpTabState } from './cdp-auxiliary-commands' +import type { CdpCommandSender, RefEntry } from './snapshot-engine' +import type { CdpBridgeState, CdpQueuedCommand } from './cdp-bridge-state' +import type { CdpDebuggerLifecycle } from './cdp-debugger-lifecycle' +import type { CdpNavigationOperations } from './cdp-navigation-operations' +import type { CdpRefResolution } from './cdp-ref-resolution' + +export type CdpScrollDirection = BrowserScrollResult extends { scrolled: infer Direction } + ? Direction + : never +export type CdpScreenshotFormat = BrowserScreenshotResult extends { format: infer Format } + ? Format + : never + +export abstract class CdpBridgeCommandModule { + constructor( + private readonly bridgeState: CdpBridgeState, + private readonly debuggerLifecycle: CdpDebuggerLifecycle, + private readonly refResolution: CdpRefResolution, + private readonly navigation: CdpNavigationOperations + ) {} + + protected get activeWebContentsId(): number | null { + return this.bridgeState.activeWebContentsId + } + + protected set activeWebContentsId(webContentsId: number | null) { + this.bridgeState.activeWebContentsId = webContentsId + } + + protected get tabState(): Map { + return this.bridgeState.tabState + } + + protected get commandQueues(): Map { + return this.bridgeState.commandQueues + } + + protected getActiveGuest(): WebContents { + return this.bridgeState.getActiveGuest() + } + + protected getRegisteredTabs(): Map { + return this.bridgeState.getRegisteredTabs() + } + + protected resolveTabId(webContentsId: number): string { + return this.bridgeState.resolveTabId(webContentsId) + } + + protected resolveTabIdSafe(webContentsId: number): string | null { + return this.bridgeState.resolveTabIdSafe(webContentsId) + } + + protected getOrCreateTabState(tabId: string): CdpTabState { + return this.bridgeState.getOrCreateTabState(tabId) + } + + protected removeDebuggerListeners(guest: WebContents, state: CdpTabState): void { + this.debuggerLifecycle.removeDebuggerListeners(guest, state) + } + + protected ensureDebuggerAttached(guest: WebContents): Promise { + return this.debuggerLifecycle.ensureDebuggerAttached(guest) + } + + protected makeCdpSender(guest: WebContents, sessionId?: string): CdpCommandSender { + return this.debuggerLifecycle.makeCdpSender(guest, sessionId) + } + + protected senderForRef(guest: WebContents, ref: RefEntry): CdpCommandSender { + return this.refResolution.senderForRef(guest, ref) + } + + protected resolveRef( + guest: WebContents, + sender: CdpCommandSender, + ref: string + ): Promise { + return this.refResolution.resolveRef(guest, sender, ref) + } + + protected scrollIntoView(sender: CdpCommandSender, backendNodeId: number): Promise { + return this.refResolution.scrollIntoView(sender, backendNodeId) + } + + protected getElementCenter( + sender: CdpCommandSender, + backendNodeId: number + ): Promise<{ cx: number; cy: number }> { + return this.refResolution.getElementCenter(sender, backendNodeId) + } + + protected getPageCoordinates( + guest: WebContents, + refEntry: RefEntry, + localCx: number, + localCy: number + ): Promise<{ cx: number; cy: number }> { + return this.refResolution.getPageCoordinates(guest, refEntry, localCx, localCy) + } + + protected getNavigationId(sender: CdpCommandSender): Promise { + return this.navigation.getNavigationId(sender) + } + + protected getPreviousHistoryEntryId(sender: CdpCommandSender): Promise { + return this.navigation.getPreviousHistoryEntryId(sender) + } + + protected waitForLoad(sender: CdpCommandSender, guest: WebContents): Promise { + return this.navigation.waitForLoad(sender, guest) + } + + protected waitForNetworkIdle( + guest: WebContents, + timeoutMs: number, + idleMs: number + ): Promise { + return this.navigation.waitForNetworkIdle(guest, timeoutMs, idleMs) + } + + protected invalidateRefMap(webContentsId: number): void { + this.bridgeState.invalidateRefMap(webContentsId) + } + + protected enqueueCommand(execute: () => Promise): Promise { + return this.bridgeState.enqueueCommand(execute) + } +} diff --git a/src/main/browser/cdp-bridge-command-set.ts b/src/main/browser/cdp-bridge-command-set.ts new file mode 100644 index 00000000000..988c69a2258 --- /dev/null +++ b/src/main/browser/cdp-bridge-command-set.ts @@ -0,0 +1,65 @@ +import type { WebContents } from 'electron' +import { CdpAuxiliaryCommands, type CdpTabState } from './cdp-auxiliary-commands' +import type { CdpCommandSender } from './snapshot-engine' +import type { CdpBridgeState } from './cdp-bridge-state' +import { CdpDebuggerLifecycle } from './cdp-debugger-lifecycle' +import { CdpElementStateCommands } from './cdp-element-state-commands' +import { CdpNavigationOperations } from './cdp-navigation-operations' +import { CdpPageCommands } from './cdp-page-commands' +import { CdpPointerCommands } from './cdp-pointer-commands' +import { CdpRefResolution } from './cdp-ref-resolution' +import { CdpTabCommands } from './cdp-tab-commands' +import { CdpTextInputCommands } from './cdp-text-input-commands' + +export class CdpBridgeCommandSet { + readonly auxiliary: CdpAuxiliaryCommands + readonly elements: CdpElementStateCommands + readonly page: CdpPageCommands + readonly pointer: CdpPointerCommands + readonly tabs: CdpTabCommands + readonly textInput: CdpTextInputCommands + + constructor(bridgeState: CdpBridgeState) { + const debuggerLifecycle = new CdpDebuggerLifecycle(bridgeState) + const navigation = new CdpNavigationOperations() + const refResolution = new CdpRefResolution(bridgeState, debuggerLifecycle, navigation) + const moduleArgs = [bridgeState, debuggerLifecycle, refResolution, navigation] as const + + this.elements = new CdpElementStateCommands(...moduleArgs) + this.page = new CdpPageCommands(...moduleArgs) + this.pointer = new CdpPointerCommands(...moduleArgs) + this.tabs = new CdpTabCommands(...moduleArgs) + this.textInput = new CdpTextInputCommands(...moduleArgs) + this.auxiliary = new CdpAuxiliaryCommands({ + run: ( + operation: (context: { + guest: WebContents + sender: CdpCommandSender + state: CdpTabState + }) => Promise + ): Promise => + bridgeState.enqueueCommand(async () => { + const guest = bridgeState.getActiveGuest() + const sender = debuggerLifecycle.makeCdpSender(guest) + await debuggerLifecycle.ensureDebuggerAttached(guest) + const state = bridgeState.getOrCreateTabState(bridgeState.resolveTabId(guest.id)) + return operation({ guest, sender, state }) + }), + runOnState: ( + operation: (context: { guest: WebContents; state: CdpTabState }) => Promise + ): Promise => + bridgeState.enqueueCommand(async () => { + const guest = bridgeState.getActiveGuest() + const state = bridgeState.getOrCreateTabState(bridgeState.resolveTabId(guest.id)) + return operation({ guest, state }) + }), + current: () => { + const guest = bridgeState.getActiveGuest() + return { + guest, + state: bridgeState.getOrCreateTabState(bridgeState.resolveTabId(guest.id)) + } + } + }) + } +} diff --git a/src/main/browser/cdp-bridge-state.ts b/src/main/browser/cdp-bridge-state.ts new file mode 100644 index 00000000000..9eed291b04d --- /dev/null +++ b/src/main/browser/cdp-bridge-state.ts @@ -0,0 +1,176 @@ +import { webContents } from 'electron' +import { BrowserError } from './browser-error' +import type { CdpTabState } from './cdp-auxiliary-commands' + +export type CdpQueuedCommand = { + execute: () => Promise + resolve: (value: unknown) => void + reject: (reason: unknown) => void +} + +export type CdpBridgeStateBindings = { + getActiveWebContentsId: () => number | null + setActiveWebContentsId: (webContentsId: number | null) => void + getRegisteredTabs: () => Map + tabState: Map + commandQueues: Map + processingQueues: Set +} + +export class CdpBridgeState { + constructor(private readonly bindings: CdpBridgeStateBindings) {} + + get activeWebContentsId(): number | null { + return this.bindings.getActiveWebContentsId() + } + + set activeWebContentsId(webContentsId: number | null) { + this.bindings.setActiveWebContentsId(webContentsId) + } + + get tabState(): Map { + return this.bindings.tabState + } + + get commandQueues(): Map { + return this.bindings.commandQueues + } + + get processingQueues(): Set { + return this.bindings.processingQueues + } + + // ── Private helpers ── + + getActiveGuest(): Electron.WebContents { + if (this.activeWebContentsId !== null) { + const guest = webContents.fromId(this.activeWebContentsId) + if (guest && !guest.isDestroyed()) { + return guest + } + // Why: webContentsId goes stale after a process swap; fall through to auto-select since the tab may have a new id. + this.activeWebContentsId = null + } + + const tabs = [...this.getRegisteredTabs()] + if (tabs.length === 0) { + throw new BrowserError( + 'browser_no_tab', + 'No browser tab is open. Use the Orca UI to open a browser tab first.' + ) + } + if (tabs.length === 1) { + this.activeWebContentsId = tabs[0][1] + } else { + throw new BrowserError( + 'browser_no_tab', + "Multiple browser tabs are open. Run 'orca tab list' and 'orca tab switch --index ' to select one." + ) + } + + const guest = webContents.fromId(this.activeWebContentsId!) + if (!guest || guest.isDestroyed()) { + this.activeWebContentsId = null + throw new BrowserError( + 'browser_debugger_detached', + "The active browser tab was closed. Run 'orca tab list' to find remaining tabs." + ) + } + return guest + } + + getRegisteredTabs(): Map { + return this.bindings.getRegisteredTabs() + } + + resolveTabId(webContentsId: number): string { + for (const [tabId, wcId] of this.getRegisteredTabs()) { + if (wcId === webContentsId) { + return tabId + } + } + throw new BrowserError('browser_debugger_detached', 'Tab is no longer registered.') + } + + resolveTabIdSafe(webContentsId: number): string | null { + for (const [tabId, wcId] of this.getRegisteredTabs()) { + if (wcId === webContentsId) { + return tabId + } + } + return null + } + + getOrCreateTabState(tabId: string): CdpTabState { + let state = this.tabState.get(tabId) + if (!state) { + state = { + navigationId: null, + snapshotResult: null, + debuggerAttached: false, + debuggerDetachListener: null, + debuggerMessageListener: null, + iframeSessions: new Map(), + capturing: false, + consoleLog: [], + networkLog: [], + intercepting: false, + interceptPatterns: [], + pausedRequests: new Map(), + networkRequestMap: new Map() + } + this.tabState.set(tabId, state) + } + return state + } + + invalidateRefMap(webContentsId: number): void { + const tabId = this.resolveTabIdSafe(webContentsId) + if (tabId) { + const state = this.tabState.get(tabId) + if (state) { + state.snapshotResult = null + state.navigationId = null + } + } + } + + async enqueueCommand(execute: () => Promise): Promise { + const guest = this.getActiveGuest() + const tabId = this.resolveTabId(guest.id) + + return new Promise((resolve, reject) => { + let queue = this.commandQueues.get(tabId) + if (!queue) { + queue = [] + this.commandQueues.set(tabId, queue) + } + queue.push({ + execute: execute as () => Promise, + resolve: resolve as (value: unknown) => void, + reject + }) + this.processQueue(tabId) + }) + } + + private async processQueue(tabId: string): Promise { + if (this.processingQueues.has(tabId)) { + return + } + this.processingQueues.add(tabId) + + const queue = this.commandQueues.get(tabId) + while (queue && queue.length > 0) { + const cmd = queue.shift()! + try { + const result = await cmd.execute() + cmd.resolve(result) + } catch (error) { + cmd.reject(error) + } + } + + this.processingQueues.delete(tabId) + } +} diff --git a/src/main/browser/cdp-bridge.ts b/src/main/browser/cdp-bridge.ts index 73dec07f2d2..dbe6dadf74d 100644 --- a/src/main/browser/cdp-bridge.ts +++ b/src/main/browser/cdp-bridge.ts @@ -1,5 +1,3 @@ -/* eslint-disable max-lines -- Why: the CDP bridge owns debugger lifecycle, ref map management, command serialization, and all browser interaction logic in one module so the browser automation boundary stays coherent. */ -import { webContents } from 'electron' import type { BrowserCaptureStartResult, BrowserCaptureStopResult, @@ -21,7 +19,6 @@ import type { BrowserInterceptEnableResult, BrowserInterceptedRequest, BrowserKeypressResult, - BrowserNetworkEntry, BrowserNetworkLogResult, BrowserPdfResult, BrowserScreenshotResult, @@ -29,7 +26,6 @@ import type { BrowserSelectAllResult, BrowserSelectResult, BrowserSnapshotResult, - BrowserTabInfo, BrowserTabListResult, BrowserTabSwitchResult, BrowserTypeResult, @@ -37,608 +33,130 @@ import type { BrowserViewportResult, BrowserWaitResult } from '../../shared/runtime-types' -import { buildSnapshot, type CdpCommandSender, type RefEntry } from './snapshot-engine' -import { insertTextThroughCdp } from './browser-text-insertion' import type { BrowserManager } from './browser-manager' -import { ANTI_DETECTION_SCRIPT } from './anti-detection' -import { BrowserError } from './browser-error' -import { CdpAuxiliaryCommands, type CdpTabState } from './cdp-auxiliary-commands' - -const CAPTURE_LOG_LIMIT = 1000 +import type { CdpAuxiliaryCommands, CdpTabState } from './cdp-auxiliary-commands' +import { CdpBridgeCommandSet } from './cdp-bridge-command-set' +import { CdpBridgeState, type CdpQueuedCommand } from './cdp-bridge-state' // Why re-exported: moved to ./browser-error so the runtime can catch it without // pulling Chromium in. Existing importers of this path keep working. export { BrowserError } from './browser-error' -type QueuedCommand = { - execute: () => Promise - resolve: (value: unknown) => void - reject: (reason: unknown) => void -} - export class CdpBridge { private activeWebContentsId: number | null = null private readonly tabState = new Map() - private readonly commandQueues = new Map() + private readonly commandQueues = new Map() private readonly processingQueues = new Set() private readonly browserManager: BrowserManager + private readonly bridgeState: CdpBridgeState + private readonly commands: CdpBridgeCommandSet private readonly auxiliaryCommands: CdpAuxiliaryCommands constructor(browserManager: BrowserManager) { this.browserManager = browserManager - this.auxiliaryCommands = new CdpAuxiliaryCommands({ - run: ( - operation: (context: { - guest: Electron.WebContents - sender: CdpCommandSender - state: CdpTabState - }) => Promise - ): Promise => - this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - const state = this.getOrCreateTabState(this.resolveTabId(guest.id)) - return operation({ guest, sender, state }) - }), - runOnState: ( - operation: (context: { guest: Electron.WebContents; state: CdpTabState }) => Promise - ): Promise => - this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const state = this.getOrCreateTabState(this.resolveTabId(guest.id)) - return operation({ guest, state }) - }), - current: () => { - const guest = this.getActiveGuest() - return { - guest, - state: this.getOrCreateTabState(this.resolveTabId(guest.id)) - } - } + this.bridgeState = new CdpBridgeState({ + getActiveWebContentsId: () => this.activeWebContentsId, + setActiveWebContentsId: (webContentsId) => { + this.activeWebContentsId = webContentsId + }, + getRegisteredTabs: () => this.getRegisteredTabs(), + tabState: this.tabState, + commandQueues: this.commandQueues, + processingQueues: this.processingQueues }) + this.commands = new CdpBridgeCommandSet(this.bridgeState) + this.auxiliaryCommands = this.commands.auxiliary } setActiveTab(webContentsId: number): void { - this.activeWebContentsId = webContentsId + this.commands.tabs.setActiveTab(webContentsId) } getActiveWebContentsId(): number | null { - return this.activeWebContentsId + return this.commands.tabs.getActiveWebContentsId() } getActivePageId(_worktreeId?: string): string | null { - if (!this.activeWebContentsId) { - return null - } - for (const [tabId, wcId] of this.getRegisteredTabs()) { - if (wcId === this.activeWebContentsId) { - return tabId - } - } - return null + return this.commands.tabs.getActivePageId(_worktreeId) } getPageInfo( _worktreeId?: string, browserPageId?: string ): { browserPageId: string; url: string; title: string } | null { - // Why: expose the same metadata lookup as other bridges, though the CDP bridge routes only one active tab. - const resolvedPageId = browserPageId ?? this.getActivePageId() - if (!resolvedPageId) { - return null - } - const webContentsId = this.getRegisteredTabs().get(resolvedPageId) - if (webContentsId == null) { - return null - } - const guest = webContents.fromId(webContentsId) - if (!guest || guest.isDestroyed()) { - return null - } - return { - browserPageId: resolvedPageId, - url: guest.getURL(), - title: guest.getTitle() - } + return this.commands.tabs.getPageInfo(_worktreeId, browserPageId) } async snapshot(): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const tabId = this.resolveTabId(guest.id) - const state = this.getOrCreateTabState(tabId) - - const result = await buildSnapshot(sender, state.iframeSessions, (sessionId) => - this.makeCdpSender(guest, sessionId) - ) - state.snapshotResult = result - - const navId = await this.getNavigationId(sender) - state.navigationId = navId - - return { - browserPageId: tabId, - snapshot: result.snapshot, - refs: result.refs, - url: guest.getURL(), - title: guest.getTitle() - } - }) + return this.commands.page.snapshot() } async click(element: string): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const node = await this.resolveRef(guest, sender, element) - const refSender = this.senderForRef(guest, node) - - await this.scrollIntoView(refSender, node.backendDOMNodeId) - const localCenter = await this.getElementCenter(refSender, node.backendDOMNodeId) - const { cx, cy } = await this.getPageCoordinates(guest, node, localCenter.cx, localCenter.cy) - - // Why: mouseMoved fires mouseenter/mouseover so sites reveal hover-dependent menus/targets before the click lands. - await sender('Input.dispatchMouseEvent', { type: 'mouseMoved', x: cx, y: cy }) - await sender('Input.dispatchMouseEvent', { - type: 'mousePressed', - x: cx, - y: cy, - button: 'left', - clickCount: 1 - }) - await sender('Input.dispatchMouseEvent', { - type: 'mouseReleased', - x: cx, - y: cy, - button: 'left', - clickCount: 1 - }) - - return { clicked: element } - }) + return this.commands.pointer.click(element) } async hover(element: string): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const node = await this.resolveRef(guest, sender, element) - const refSender = this.senderForRef(guest, node) - await this.scrollIntoView(refSender, node.backendDOMNodeId) - const localCenter = await this.getElementCenter(refSender, node.backendDOMNodeId) - const { cx, cy } = await this.getPageCoordinates(guest, node, localCenter.cx, localCenter.cy) - - await sender('Input.dispatchMouseEvent', { type: 'mouseMoved', x: cx, y: cy }) - - return { hovered: element } - }) + return this.commands.pointer.hover(element) } async drag(fromElement: string, toElement: string): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const fromNode = await this.resolveRef(guest, sender, fromElement) - const toNode = await this.resolveRef(guest, sender, toElement) - const fromSender = this.senderForRef(guest, fromNode) - const toSender = this.senderForRef(guest, toNode) - - await this.scrollIntoView(fromSender, fromNode.backendDOMNodeId) - const fromLocal = await this.getElementCenter(fromSender, fromNode.backendDOMNodeId) - const from = await this.getPageCoordinates(guest, fromNode, fromLocal.cx, fromLocal.cy) - const toLocal = await this.getElementCenter(toSender, toNode.backendDOMNodeId) - const to = await this.getPageCoordinates(guest, toNode, toLocal.cx, toLocal.cy) - - // Why: interpolate the drag so intermediate elements fire dragenter/dragover, which many drag-and-drop libs require. - await sender('Input.dispatchMouseEvent', { type: 'mouseMoved', x: from.cx, y: from.cy }) - await sender('Input.dispatchMouseEvent', { - type: 'mousePressed', - x: from.cx, - y: from.cy, - button: 'left' - }) - - const steps = 10 - for (let i = 1; i <= steps; i++) { - const x = from.cx + ((to.cx - from.cx) * i) / steps - const y = from.cy + ((to.cy - from.cy) * i) / steps - await sender('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y, buttons: 1 }) - await new Promise((r) => setTimeout(r, 10)) - } - - await sender('Input.dispatchMouseEvent', { - type: 'mouseReleased', - x: to.cx, - y: to.cy, - button: 'left' - }) - - return { dragged: { from: fromElement, to: toElement } } - }) + return this.commands.pointer.drag(fromElement, toElement) } async uploadFile(element: string, filePaths: string[]): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const node = await this.resolveRef(guest, sender, element) - const refSender = this.senderForRef(guest, node) - await refSender('DOM.setFileInputFiles', { - files: filePaths, - backendNodeId: node.backendDOMNodeId - }) - - return { uploaded: filePaths.length } - }) + return this.commands.elements.uploadFile(element, filePaths) } async goto(url: string): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const { errorText } = (await sender('Page.navigate', { url })) as { - errorText?: string - } - - if (errorText) { - throw new BrowserError('browser_navigation_failed', `Navigation failed: ${errorText}`) - } - - await this.waitForLoad(sender, guest) - this.invalidateRefMap(guest.id) - - return { url: guest.getURL(), title: guest.getTitle() } - }) + return this.commands.page.goto(url) } async fill(element: string, value: string): Promise { - return this.enqueueCommand(async () => { - const guest = this.getActiveGuest() - const sender = this.makeCdpSender(guest) - await this.ensureDebuggerAttached(guest) - - const node = await this.resolveRef(guest, sender, element) - const refSender = this.senderForRef(guest, node) - - await refSender('DOM.focus', { backendNodeId: node.backendDOMNodeId }) - - // Why: select-all + delete clears the existing value before typing, matching Playwright/agent-browser fill(). - await sender('Input.dispatchKeyEvent', { - type: 'keyDown', - key: 'a', - modifiers: process.platform === 'darwin' ? 4 : 2 - }) - await sender('Input.dispatchKeyEvent', { - type: 'keyUp', - key: 'a', - modifiers: process.platform === 'darwin' ? 4 : 2 - }) - await sender('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Delete' }) - await sender('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Delete' }) - - await insertTextThroughCdp(sender, value) - - // Why: React's synthetic listeners ignore native key events, so dispatch input/change so controlled components update. - // Why: use refSender for iframe sessions so document.activeElement is the focused element inside the iframe, not the parent