From 016ad780862b92ee6de48f62ccc14a401779f218 Mon Sep 17 00:00:00 2001 From: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:22:18 -0700 Subject: [PATCH] fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q (#1061) --- .github/workflows/build-windows.yml | 42 +- .github/workflows/build.yml | 11 +- .github/workflows/e2e-agent-review.yml | 7 +- .github/workflows/release-packages.yml | 22 +- .github/workflows/release.yml | 195 +- .github/workflows/test.yml | 9 +- app/package.json | 6 +- app/src-tauri/Cargo.lock | 2747 +++++++++++++++++++++-- app/src-tauri/Cargo.toml | 17 +- app/src-tauri/src/core_process.rs | 628 +----- app/src-tauri/src/core_process_tests.rs | 223 +- app/src-tauri/src/core_update.rs | 776 ------- app/src-tauri/src/lib.rs | 225 +- app/src-tauri/tauri.conf.json | 7 +- package.json | 1 - scripts/release/stage-sidecar.sh | 48 - scripts/stage-core-sidecar.mjs | 126 -- 17 files changed, 2811 insertions(+), 2279 deletions(-) delete mode 100644 app/src-tauri/src/core_update.rs delete mode 100755 scripts/release/stage-sidecar.sh delete mode 100644 scripts/stage-core-sidecar.mjs diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6e5c9bb7f..397850676 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -71,46 +71,8 @@ jobs: # vite build runs via tauri.conf.json's beforeBuildCommand during the # "Build Tauri app" step below — no separate frontend build needed. - - name: Resolve core manifest and binary names - id: core-paths - shell: bash - run: | - if [ -f "openhuman_core/Cargo.toml" ]; then - CORE_DIR="openhuman_core" - elif [ -f "rust-core/Cargo.toml" ]; then - CORE_DIR="rust-core" - elif [ -f "Cargo.toml" ] && grep -q '^name = "openhuman"' Cargo.toml; then - CORE_DIR="." - else - echo "No core Cargo manifest found" - exit 1 - fi - SIDE_CAR_BASE="$(node -e "const fs=require('fs');const c=JSON.parse(fs.readFileSync('app/src-tauri/tauri.conf.json','utf8'));const b=(c.bundle&&Array.isArray(c.bundle.externalBin)&&c.bundle.externalBin[0])||'binaries/openhuman-core';process.stdout.write(String(b).split('/').pop());")" - CORE_BIN_NAME="${SIDE_CAR_BASE}" - echo "core_dir=$CORE_DIR" >> "$GITHUB_OUTPUT" - echo "core_manifest=$CORE_DIR/Cargo.toml" >> "$GITHUB_OUTPUT" - echo "core_target_dir=target/x86_64-pc-windows-msvc/release" >> "$GITHUB_OUTPUT" - echo "core_bin_name=$CORE_BIN_NAME" >> "$GITHUB_OUTPUT" - echo "sidecar_base=$SIDE_CAR_BASE" >> "$GITHUB_OUTPUT" - - name: Build sidecar core binary - shell: bash - run: | - cargo build \ - --manifest-path "$CORE_MANIFEST" \ - --release \ - --target x86_64-pc-windows-msvc \ - --bin "$CORE_BIN_NAME" - env: - CORE_MANIFEST: ${{ steps.core-paths.outputs.core_manifest }} - CORE_BIN_NAME: ${{ steps.core-paths.outputs.core_bin_name }} - - name: Stage sidecar for Tauri bundler - shell: bash - run: | - bash scripts/release/stage-sidecar.sh \ - x86_64-pc-windows-msvc \ - "${{ steps.core-paths.outputs.core_target_dir }}" \ - "${{ steps.core-paths.outputs.core_bin_name }}" \ - "${{ steps.core-paths.outputs.sidecar_base }}" + # Core is linked into the Tauri binary as a path dep — no separate + # sidecar build / stage / path-resolution step needed. - name: Define Tauri configuration overrides id: config-overrides # `prepareTauriConfig.js` only emits the Windows DigiCert sign diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a212ae539..1b963e8e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,19 +61,14 @@ jobs: - name: Install cmake (for whisper-rs) run: apt-get update && apt-get install -y --no-install-recommends cmake && rm -rf /var/lib/apt/lists/* - - name: Build sidecar core binary - run: cargo build --profile ci --target x86_64-unknown-linux-gnu --bin openhuman-core - - name: Stage sidecar for Tauri bundler - run: | - mkdir -p app/src-tauri/binaries - cp target/x86_64-unknown-linux-gnu/ci/openhuman-core app/src-tauri/binaries/openhuman-core-x86_64-unknown-linux-gnu - chmod +x app/src-tauri/binaries/openhuman-core-x86_64-unknown-linux-gnu + # Core is linked into the Tauri binary as a path dep — no separate + # sidecar build / stage step needed. - name: Build Tauri app (CEF default) working-directory: app run: | # Skip tsc in beforeBuildCommand — typechecking runs in the dedicated # `typecheck` workflow, so doing it again here is duplicated CI time. - TAURI_CONFIG_OVERRIDE='{"build":{"beforeBuildCommand":"npx vite build && pnpm run core:stage"},"plugins":{"updater":{"active":false}}}' + TAURI_CONFIG_OVERRIDE='{"build":{"beforeBuildCommand":"npx vite build"},"plugins":{"updater":{"active":false}}}' cargo tauri build -c "$TAURI_CONFIG_OVERRIDE" --bundles deb env: NODE_ENV: production diff --git a/.github/workflows/e2e-agent-review.yml b/.github/workflows/e2e-agent-review.yml index 98f67f2cf..e80434d94 100644 --- a/.github/workflows/e2e-agent-review.yml +++ b/.github/workflows/e2e-agent-review.yml @@ -89,12 +89,7 @@ jobs: - name: Build E2E app if: steps.gate.outputs.present == 'true' run: pnpm --filter openhuman-app test:e2e:build - - name: Stage sidecar next to app binary - if: steps.gate.outputs.present == 'true' - run: | - cp app/src-tauri/binaries/openhuman-core-x86_64-unknown-linux-gnu \ - app/src-tauri/target/debug/openhuman-core-x86_64-unknown-linux-gnu - chmod +x app/src-tauri/target/debug/openhuman-core-x86_64-unknown-linux-gnu + # Core is linked in-process — no sidecar staging needed. - name: Run agent-review E2E spec under Xvfb if: steps.gate.outputs.present == 'true' run: | diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 30a09108e..25f29d13a 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -1,19 +1,17 @@ --- name: Release Packages -# Triggered after the main release.yml publishes a release. -# By the time this fires, macOS (aarch64 + x86_64) and Linux x86_64 -# CLI tarballs are already attached to the release by release.yml. +# DISABLED while core distribution is Docker-only — see PR #1061. # -# This workflow adds: -# 1. Linux arm64 CLI tarball -# 2. Homebrew tap formula update -# 3. Debian apt repository (gh-pages) -# 4. npm package publish -# 5. Smoke tests for each channel -# 6. One-time backlog issue for future package managers +# This workflow built standalone CLI tarballs / .deb / Homebrew / npm +# packages that wrapped the `openhuman-core` binary. Now that the core is +# linked into the Tauri shell as a path dep and shipped via the desktop +# bundle (with Docker as the only headless channel), there is no separate +# CLI binary to redistribute. Re-enable by switching the trigger back to +# `on: release: types: [published]` once a standalone CLI binary is +# re-introduced — every job below still references `package-cli-tarball.sh` +# and the `openhuman-core` cargo bin, so they will resume working then. on: - release: - types: [published] + workflow_dispatch: permissions: contents: write pages: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 737d56156..e6799929d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -427,84 +427,11 @@ jobs: # Note: vite build runs via tauri.conf.json's beforeBuildCommand during # the "Build and package Tauri app" step below. A separate frontend build # here would just double memory pressure (sentry-vite-plugin peaks hard). - - name: Resolve core manifest and binary names - id: core-paths - shell: bash - run: | - if [ -f "openhuman_core/Cargo.toml" ]; then - CORE_DIR="openhuman_core" - elif [ -f "rust-core/Cargo.toml" ]; then - CORE_DIR="rust-core" - elif [ -f "Cargo.toml" ] && grep -q '^name = "openhuman"' Cargo.toml; then - CORE_DIR="." - else - echo "No core Cargo manifest found (expected root Cargo.toml with openhuman, openhuman_core/Cargo.toml, or rust-core/Cargo.toml)" - exit 1 - fi - SIDE_CAR_BASE="$(node -e "const fs=require('fs');const c=JSON.parse(fs.readFileSync('app/src-tauri/tauri.conf.json','utf8'));const b=(c.bundle&&Array.isArray(c.bundle.externalBin)&&c.bundle.externalBin[0])||'binaries/openhuman-core';process.stdout.write(String(b).split('/').pop());")" - CORE_BIN_NAME="${SIDE_CAR_BASE}" - BUILD_PROFILE="${BUILD_PROFILE:-release}" - echo "core_dir=$CORE_DIR" >> "$GITHUB_OUTPUT" - echo "core_manifest=$CORE_DIR/Cargo.toml" >> "$GITHUB_OUTPUT" - # Cargo workspace artifacts are under repo root target/, not /target/ - echo "core_target_dir=target/$MATRIX_TARGET/$BUILD_PROFILE" >> "$GITHUB_OUTPUT" - echo "build_profile=$BUILD_PROFILE" >> "$GITHUB_OUTPUT" - echo "core_bin_name=$CORE_BIN_NAME" >> "$GITHUB_OUTPUT" - echo "sidecar_base=$SIDE_CAR_BASE" >> "$GITHUB_OUTPUT" - env: - MATRIX_TARGET: ${{ matrix.settings.target }} - BUILD_PROFILE: ${{ inputs.build_target == 'staging' && 'debug' || 'release' }} - - name: Build sidecar core binary - shell: bash - run: | - if [ "$BUILD_PROFILE" = "release" ]; then - cargo build \ - --manifest-path "$CORE_MANIFEST" \ - --release \ - --target "$MATRIX_TARGET" \ - --bin "$CORE_BIN_NAME" - else - cargo build \ - --manifest-path "$CORE_MANIFEST" \ - --target "$MATRIX_TARGET" \ - --bin "$CORE_BIN_NAME" - fi - env: - MATRIX_TARGET: ${{ matrix.settings.target }} - BUILD_PROFILE: ${{ steps.core-paths.outputs.build_profile }} - CORE_MANIFEST: ${{ steps.core-paths.outputs.core_manifest }} - CORE_BIN_NAME: ${{ steps.core-paths.outputs.core_bin_name }} - OPENHUMAN_APP_ENV: ${{ inputs.build_target == 'staging' && 'staging' || 'production' }} - # Core (Rust openhuman sidecar) Sentry DSN — separate Sentry project - # from the React frontend and the Tauri shell. - OPENHUMAN_SENTRY_DSN: ${{ vars.OPENHUMAN_CORE_SENTRY_DSN }} - # Sentry release tracking (#405): `option_env!("OPENHUMAN_BUILD_SHA")` - # in src/main.rs bakes the short SHA into the release tag - # (`openhuman@+`) so core events match the frontend. - OPENHUMAN_BUILD_SHA: ${{ needs.prepare-build.outputs.sha }} - - name: Stage sidecar for Tauri bundler - shell: bash - run: | - bash scripts/release/stage-sidecar.sh \ - "${{ matrix.settings.target }}" \ - "${{ steps.core-paths.outputs.core_target_dir }}" \ - "${{ steps.core-paths.outputs.core_bin_name }}" \ - "${{ steps.core-paths.outputs.sidecar_base }}" - - name: Resolve standalone core CLI artifact path - id: cli-paths - shell: bash - run: | - BASE_DIR="$CORE_TARGET_DIR" - EXE_SUFFIX="" - if [[ "$MATRIX_TARGET" == *"windows"* ]]; then - EXE_SUFFIX=".exe" - fi - echo "base_dir=$BASE_DIR" >> "$GITHUB_OUTPUT" - echo "cli_path=$BASE_DIR/${CORE_BIN_NAME}${EXE_SUFFIX}" >> "$GITHUB_OUTPUT" - env: - MATRIX_TARGET: ${{ matrix.settings.target }} - CORE_TARGET_DIR: ${{ steps.core-paths.outputs.core_target_dir }} - CORE_BIN_NAME: ${{ steps.core-paths.outputs.core_bin_name }} + # + # The core no longer ships as a sidecar — it's linked into the Tauri + # binary as a path dep (`openhuman_core` in app/src-tauri/Cargo.toml) + # and the JSON-RPC server runs as an in-process tokio task. Docker is + # the only standalone distribution channel for the core CLI now. # CEF is the default runtime — we build via the vendored tauri-cli so # the bundler copies Chromium Embedded Framework files into the .app / @@ -596,37 +523,12 @@ jobs: MATRIX_TARGET: ${{ matrix.settings.target }} run: | set -euo pipefail - deps_dir="target/${MATRIX_TARGET}/release/deps" - if [ -d "$deps_dir" ]; then - echo "==> Uploading core symbols from $deps_dir to ${SENTRY_PROJECT}" - bash scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir" - else - echo "==> Skipping $deps_dir (not present)" - fi - - name: Upload Tauri shell debug symbols to Sentry - if: - needs.prepare-build.outputs.release_enabled == 'true' && env.SENTRY_AUTH_TOKEN - != '' - shell: bash - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_ORG: ${{ vars.SENTRY_ORG }} - SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT_TAURI }} - # Must match the release tag the running shell binary reports - # (`openhuman@+`, see `build_sentry_release_tag` in - # app/src-tauri/src/lib.rs). If this drifts, DIFs attach to a - # different release than events and stack traces stay - # un-symbolicated. - SENTRY_RELEASE: - openhuman@${{ needs.prepare-build.outputs.version }}+${{ - needs.prepare-build.outputs.sha }} - VERSION: ${{ needs.prepare-build.outputs.version }} - MATRIX_TARGET: ${{ matrix.settings.target }} - run: | - set -euo pipefail + # Core is linked into the Tauri binary as a path dep, so all Rust + # debug info — core + shell — lives under the shell's target dir. + # upload-dif scans recursively. deps_dir="app/src-tauri/target/${MATRIX_TARGET}/release/deps" if [ -d "$deps_dir" ]; then - echo "==> Uploading Tauri shell symbols from $deps_dir to ${SENTRY_PROJECT}" + echo "==> Uploading symbols from $deps_dir to ${SENTRY_PROJECT}" bash scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir" else echo "==> Skipping $deps_dir (not present)" @@ -705,7 +607,7 @@ jobs: echo "bundle_dir=$BUNDLE_DIR" >> "$GITHUB_OUTPUT" echo "Found .app at: $APP_PATH" echo "Bundle dir: $BUNDLE_DIR" - - name: Re-sign sidecar with hardened runtime and notarize + - name: Sign and notarize macOS .app if: matrix.settings.platform == 'macos-latest' shell: bash env: @@ -746,78 +648,13 @@ jobs: "${{ steps.locate-app.outputs.bundle_dir }}" \ "${{ needs.prepare-build.outputs.version }}" \ "${{ matrix.settings.target }}" - - name: Verify macOS app bundle sidecar layout + - name: Verify macOS notarization staple if: matrix.settings.platform == 'macos-latest' shell: bash run: | APP_PATH="${{ steps.locate-app.outputs.app_path }}" - echo "Inspecting bundle at: $APP_PATH" - ls -la "$APP_PATH/Contents/MacOS" - ls -la "$APP_PATH/Contents/Resources" | grep openhuman || true - - # Sidecar may be in MacOS/ or Resources/ depending on Tauri version - FOUND=false - if ls "$APP_PATH/Contents/MacOS"/openhuman* 2>/dev/null | grep -qv OpenHuman; then - echo "Sidecar found in Contents/MacOS/" - FOUND=true - fi - if ls "$APP_PATH/Contents/Resources"/openhuman-* 2>/dev/null; then - echo "Sidecar found in Contents/Resources/" - FOUND=true - fi - if [ "$FOUND" = "false" ]; then - echo "WARNING: Sidecar binary not found in expected locations" - fi - - # Verify notarization staple - echo "Checking staple..." + echo "Checking staple at: $APP_PATH" xcrun stapler validate "$APP_PATH" || echo "WARNING: Staple validation failed" - - name: Package CLI tarball and upload to release (unix) - if: - matrix.settings.platform != 'windows-latest' && needs.prepare-build.outputs.release_enabled - == 'true' - shell: bash - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # For macOS, prefer the notarized binary from inside the .app bundle - if [[ "${{ matrix.settings.platform }}" == "macos-latest" ]]; then - APP_PATH="${{ steps.locate-app.outputs.app_path }}" - BIN=$(find "$APP_PATH/Contents/MacOS" -maxdepth 1 -name "openhuman-core-*" \ - ! -name "*.sig" 2>/dev/null | head -1 || true) - [[ -z "$BIN" ]] && BIN=$(find "$APP_PATH/Contents/Resources" -maxdepth 1 \ - -name "openhuman-core-*" ! -name "*.sig" 2>/dev/null | head -1 || true) - if [[ -z "$BIN" ]]; then - echo "[pkg] Falling back to target dir binary (no notarized sidecar found)" - BIN="${{ steps.cli-paths.outputs.cli_path }}" - fi - else - BIN="${{ steps.cli-paths.outputs.cli_path }}" - fi - bash scripts/release/package-cli-tarball.sh \ - "$BIN" \ - "${{ needs.prepare-build.outputs.version }}" \ - "${{ matrix.settings.target }}" - - name: Package CLI zip and upload to release (windows) - if: - matrix.settings.platform == 'windows-latest' && needs.prepare-build.outputs.release_enabled - == 'true' - shell: pwsh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - $Version = "${{ needs.prepare-build.outputs.version }}" - $Target = "${{ matrix.settings.target }}" - $BinPath = "${{ steps.cli-paths.outputs.cli_path }}" - $ZipName = "openhuman-core-${Version}-${Target}.zip" - $Work = New-Item -ItemType Directory -Path (Join-Path $env:TEMP "cli-pkg-$(Get-Random)") - Copy-Item $BinPath (Join-Path $Work.FullName "openhuman-core.exe") - Compress-Archive -Path (Join-Path $Work.FullName "openhuman-core.exe") -DestinationPath $ZipName - $Hash = (Get-FileHash -Path $ZipName -Algorithm SHA256).Hash.ToLowerInvariant() - Set-Content -Path "${ZipName}.sha256" -Value $Hash -NoNewline - Write-Host "[package-cli] Created $ZipName (sha256: $Hash)" - gh release upload "v${Version}" $ZipName "${ZipName}.sha256" --repo tinyhumansai/openhuman --clobber - Write-Host "[package-cli] Uploaded $ZipName to v${Version}" - name: Upload staging desktop bundles if: needs.prepare-build.outputs.release_enabled != 'true' uses: actions/upload-artifact@v4 @@ -828,14 +665,6 @@ jobs: path: | app/src-tauri/target/${{ matrix.settings.target }}/${{ inputs.build_target == 'staging' && 'debug' || 'release' }}/bundle/** target/${{ matrix.settings.target }}/${{ inputs.build_target == 'staging' && 'debug' || 'release' }}/bundle/** - - name: Upload standalone CLI artifacts - uses: actions/upload-artifact@v4 - with: - name: - standalone-bins-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix - }} - path: | - ${{ steps.cli-paths.outputs.cli_path }} # ========================================================================= # Phase 3b: Build & push Docker image (runs parallel with build-desktop) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b292206c3..67deab7b6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -130,13 +130,8 @@ jobs: - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.9 - - name: Build sidecar core binary - run: cargo build --profile ci --target x86_64-unknown-linux-gnu --bin openhuman-core - - name: Stage sidecar for Tauri shell tests - run: | - mkdir -p app/src-tauri/binaries - cp target/x86_64-unknown-linux-gnu/ci/openhuman-core app/src-tauri/binaries/openhuman-core-x86_64-unknown-linux-gnu - chmod +x app/src-tauri/binaries/openhuman-core-x86_64-unknown-linux-gnu + # Core is linked into the Tauri binary as a path dep, so the shell's + # cargo test pulls it in automatically — no separate sidecar build. - name: Test Tauri shell (OpenHuman) run: cargo test --manifest-path app/src-tauri/Cargo.toml diff --git a/app/package.json b/app/package.json index c09af6f7f..1603186b8 100644 --- a/app/package.json +++ b/app/package.json @@ -8,10 +8,10 @@ "scripts": { "dev": "vite", "dev:web": "vite", - "dev:app": "pnpm tauri:ensure && export CEF_PATH=\"$HOME/Library/Caches/tauri-cef\" && pnpm core:stage && bash ../scripts/setup-chromium-safe-storage.sh && source ../scripts/load-dotenv.sh && APPLE_SIGNING_IDENTITY='OpenHuman Dev Signer' cargo tauri dev", + "dev:app": "pnpm tauri:ensure && export CEF_PATH=\"$HOME/Library/Caches/tauri-cef\" && bash ../scripts/setup-chromium-safe-storage.sh && source ../scripts/load-dotenv.sh && APPLE_SIGNING_IDENTITY='OpenHuman Dev Signer' cargo tauri dev", "dev:cef": "pnpm dev:app", - "dev:wry": "pnpm tauri:ensure && export CEF_PATH=\"$HOME/Library/Caches/tauri-cef\" && pnpm core:stage && source ../scripts/load-dotenv.sh && cargo tauri dev --no-default-features --features wry", - "core:stage": "node ../scripts/stage-core-sidecar.mjs", + "dev:wry": "pnpm tauri:ensure && export CEF_PATH=\"$HOME/Library/Caches/tauri-cef\" && source ../scripts/load-dotenv.sh && cargo tauri dev --no-default-features --features wry", + "core:stage": "echo '[core:stage] no-op — core is linked in-process; sidecar removed (PR #1061)'", "tauri:ensure": "bash ../scripts/ensure-tauri-cli.sh", "build": "tsc && vite build", "build:app": "tsc && vite build", diff --git a/app/src-tauri/Cargo.lock b/app/src-tauri/Cargo.lock index 088657811..bd66fb6ca 100644 --- a/app/src-tauri/Cargo.lock +++ b/app/src-tauri/Cargo.lock @@ -9,32 +9,30 @@ dependencies = [ "anyhow", "async-trait", "base64 0.22.1", - "block2", + "block2 0.6.2", "cef", "chrono", - "directories", + "directories 5.0.1", "env_logger", - "flate2", "futures-util", "hex", "log", "mac-notification-sys", "nix 0.29.0", "notify-rust", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", "objc2-user-notifications", + "openhuman", "parking_lot", "rand 0.9.2", "reqwest 0.12.28", "rusqlite", "rustls", - "semver", "sentry", "serde", "serde_json", - "tar", "tauri", "tauri-build", "tauri-plugin-deep-link", @@ -45,9 +43,8 @@ dependencies = [ "tauri-runtime-cef", "tempfile", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.24.0", "toml 0.8.2", - "zip 2.4.2", ] [[package]] @@ -65,6 +62,41 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -74,6 +106,28 @@ dependencies = [ "memchr", ] +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.11.0", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -148,18 +202,61 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "x11rb", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures 0.2.17", + "password-hash", +] + [[package]] name = "async-broadcast" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "futures-core", "pin-project-lite", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -172,6 +269,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-executor" version = "1.14.0" @@ -186,6 +295,29 @@ dependencies = [ "slab", ] +[[package]] +name = "async-imap" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78dceaba06f029d8f4d7df20addd4b7370a30206e3926267ecda2915b0f3f66" +dependencies = [ + "async-channel 2.5.0", + "async-compression", + "base64 0.22.1", + "bytes", + "chrono", + "futures", + "imap-proto", + "log", + "nom 7.1.3", + "pin-project", + "pin-utils", + "self_cell", + "stop-token", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "async-io" version = "2.6.0" @@ -210,7 +342,7 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -221,14 +353,14 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener", + "event-listener 5.4.1", "futures-lite", "rustix", ] @@ -336,6 +468,71 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "axum-macros", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite 0.29.0", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -363,6 +560,32 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.11.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.117", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -393,6 +616,21 @@ dependencies = [ "serde_core", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.4" @@ -402,13 +640,31 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + [[package]] name = "block2" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2", + "objc2 0.6.4", ] [[package]] @@ -417,7 +673,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-task", "futures-io", "futures-lite", @@ -442,6 +698,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.11.1" @@ -547,7 +809,7 @@ checksum = "a5dad6495c583fedab04a24f6fc08274c59a28b33967ca87709398e1f11c2ebe" dependencies = [ "cef-dll-sys", "libloading 0.9.0", - "objc2", + "objc2 0.6.4", "windows-sys 0.61.2", ] @@ -569,6 +831,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cfb" version = "0.7.3" @@ -602,6 +873,41 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20 0.9.1", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.44" @@ -616,6 +922,38 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf 0.12.1", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", + "zeroize", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.9", +] + [[package]] name = "clap" version = "4.6.1" @@ -638,6 +976,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "660c0520455b1013b9bcb0393d5f643d7e4454fb69c915b8d6d2aa0e9a45acc3" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.6.1" @@ -656,6 +1003,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + [[package]] name = "cmake" version = "0.1.58" @@ -665,6 +1021,27 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + +[[package]] +name = "cocoa" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667fdc068627a2816b9ff831201dd9864249d6ee8d190b9532357f1fc0f61ea7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics 0.21.0", + "foreign-types 0.3.2", + "libc", + "objc", +] + [[package]] name = "colorchoice" version = "1.0.5" @@ -681,6 +1058,22 @@ dependencies = [ "memchr", ] +[[package]] +name = "compression-codecs" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" +dependencies = [ + "compression-core", + "flate2", +] + +[[package]] +name = "compression-core" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -702,6 +1095,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const-random" version = "0.1.18" @@ -757,22 +1156,85 @@ dependencies = [ "url", ] +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.7", "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.7.0", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a67c4378cf203eace8fb6567847eb641fd6ff933c1145a115c6ee820ebb978" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "core-graphics" version = "0.25.0" @@ -780,9 +1242,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -793,10 +1255,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "libc", ] +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys 0.8.7", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys 0.8.7", + "coreaudio-rs", + "dasp_sample", + "jni 0.21.1", + "js-sys", + "libc", + "mach2", + "ndk 0.8.0", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.54.0", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -806,6 +1311,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -815,6 +1329,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cron" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8c3e73077b4b4a6ab1ea5047c37c57aee77657bc8ecd6f29b0af082d0b0c07" +dependencies = [ + "chrono", + "nom 7.1.3", + "once_cell", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -843,9 +1368,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cssparser" version = "0.29.6" @@ -896,6 +1431,24 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "darling" version = "0.23.0" @@ -930,6 +1483,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + [[package]] name = "data-encoding" version = "2.10.0" @@ -1018,14 +1577,40 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dialoguer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96" +dependencies = [ + "console", + "fuzzy-matcher", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid", + "crypto-common 0.2.1", + "ctutils", ] [[package]] @@ -1043,6 +1628,24 @@ dependencies = [ "dirs-sys 0.4.1", ] +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys 0.5.0", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + [[package]] name = "dirs" version = "6.0.0" @@ -1083,9 +1686,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.6.2", "libc", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -1155,6 +1758,12 @@ dependencies = [ "tendril 0.5.0", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "download-cef" version = "2.3.1" @@ -1210,6 +1819,28 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "email-encoding" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9298e6504d9b9e780ed3f7dfd43a61be8cd0e09eb07f7706a945b0072b6670b6" +dependencies = [ + "base64 0.22.1", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" + [[package]] name = "embed-resource" version = "3.0.8" @@ -1242,6 +1873,52 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" +[[package]] +name = "engineioxide" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b48069eef4227bde0e5a8e0601ddabfbdef887c05b831cd314d2990726a461" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "rand 0.8.5", + "serde", + "serde_json", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tokio-tungstenite 0.24.0", + "tower-layer", + "tower-service", +] + +[[package]] +name = "enigo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cf6f550bbbdd5fe66f39d429cb2604bcdacbf00dca0f5bbe2e9306a0009b7c6" +dependencies = [ + "core-foundation 0.10.1", + "core-graphics 0.24.0", + "foreign-types-shared 0.3.1", + "libc", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "windows 0.58.0", + "xkbcommon", + "xkeysym", +] + [[package]] name = "enumflags2" version = "0.7.12" @@ -1313,6 +1990,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.4.1" @@ -1330,10 +2019,16 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener", + "event-listener 5.4.1", "pin-project-lite", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1352,6 +2047,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + [[package]] name = "fdeflate" version = "0.3.7" @@ -1416,6 +2117,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1423,7 +2133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -1437,6 +2147,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1452,6 +2168,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -1468,6 +2194,21 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.32" @@ -1543,6 +2284,7 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1553,6 +2295,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -1701,10 +2452,21 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.32.3" @@ -1804,8 +2566,8 @@ checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" dependencies = [ "crossbeam-channel", "keyboard-types", - "objc2", - "objc2-app-kit", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "once_cell", "serde", "thiserror 2.0.18", @@ -1896,6 +2658,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1923,6 +2696,18 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashify" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd1246c0e5493286aeb2dde35b1f4eb9c4ce00e628641210a5e553fc001a1f26" +dependencies = [ + "indexmap 2.13.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "hashlink" version = "0.10.0" @@ -1956,6 +2741,24 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.2", +] + [[package]] name = "hostname" version = "0.4.2" @@ -1967,6 +2770,40 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "hound" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" + +[[package]] +name = "html2md" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cff9891f2e0d9048927fbdfc28b11bf378f6a93c7ba70b23d0fbee9af6071b4" +dependencies = [ + "html5ever 0.27.0", + "jni 0.19.0", + "lazy_static", + "markup5ever_rcdom", + "percent-encoding", + "regex", +] + +[[package]] +name = "html5ever" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +dependencies = [ + "log", + "mac", + "markup5ever 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "html5ever" version = "0.29.1" @@ -2034,6 +2871,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.8.1" @@ -2048,6 +2894,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -2070,7 +2917,23 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.6", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] @@ -2103,7 +2966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", - "core-foundation-sys", + "core-foundation-sys 0.8.7", "iana-time-zone-haiku", "js-sys", "log", @@ -2127,7 +2990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -2244,6 +3107,31 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png 0.18.1", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "imap-proto" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f6af35c6a517aea5c72314abe90134980d2ae6a763809b50c208b3e429d71f" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -2289,6 +3177,15 @@ dependencies = [ "cfb", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -2330,6 +3227,24 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -2383,6 +3298,20 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", +] + [[package]] name = "jni" version = "0.21.1" @@ -2494,12 +3423,41 @@ dependencies = [ "selectors 0.24.0", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128fmt" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "lettre" +version = "0.11.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dabda5859ee7c06b995b9d1165aa52c39110e079ef609db97178d86aeb051fa7" +dependencies = [ + "base64 0.22.1", + "email-encoding", + "email_address", + "fastrand", + "httpdate", + "idna", + "mime", + "nom 8.0.0", + "percent-encoding", + "quoted_printable", + "rustls", + "socket2", + "tokio", + "url", + "webpki-roots 1.0.6", +] + [[package]] name = "libappindicator" version = "0.9.0" @@ -2555,6 +3513,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + [[package]] name = "libloading" version = "0.9.0" @@ -2627,6 +3595,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "mac" version = "0.1.1" @@ -2640,11 +3619,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29a16783dd1a47849b8c8133c9cd3eb2112cfbc6901670af3dba47c8bbfb07d3" dependencies = [ "cc", - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", "time", ] +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "mail-parser" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82a3d6522697593ba4c683e0a6ee5a40fee93bc1a525e3cc6eeb3da11fd8897" +dependencies = [ + "hashify", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +dependencies = [ + "log", + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache 0.8.9", + "string_cache_codegen 0.5.4", + "tendril 0.4.3", +] + [[package]] name = "markup5ever" version = "0.14.1" @@ -2670,6 +3690,18 @@ dependencies = [ "web_atoms", ] +[[package]] +name = "markup5ever_rcdom" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18" +dependencies = [ + "html5ever 0.27.0", + "markup5ever 0.12.1", + "tendril 0.4.3", + "xml5ever", +] + [[package]] name = "match_token" version = "0.1.0" @@ -2681,18 +3713,52 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.2", +] + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -2708,6 +3774,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "minisign-verify" version = "0.2.5" @@ -2735,6 +3817,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "muda" version = "0.17.1" @@ -2745,17 +3837,48 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2", - "objc2-app-kit", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "once_cell", - "png", + "png 0.17.16", "serde", "thiserror 2.0.18", "windows-sys 0.60.2", ] +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.11.0", + "jni-sys 0.3.1", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] + [[package]] name = "ndk" version = "0.9.0" @@ -2765,7 +3888,7 @@ dependencies = [ "bitflags 2.11.0", "jni-sys 0.3.1", "log", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -2777,6 +3900,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.1", +] + [[package]] name = "ndk-sys" version = "0.6.0+11769913" @@ -2822,6 +3954,25 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "notify-rust" version = "4.15.0" @@ -2837,12 +3988,51 @@ dependencies = [ "zbus", ] +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-conv" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2874,6 +4064,31 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + [[package]] name = "objc2" version = "0.6.4" @@ -2884,6 +4099,22 @@ dependencies = [ "objc2-exception-helper", ] +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", +] + [[package]] name = "objc2-app-kit" version = "0.3.2" @@ -2891,18 +4122,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.6.2", "libc", - "objc2", + "objc2 0.6.4", "objc2-cloud-kit", - "objc2-core-data", + "objc2-core-data 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-core-image", + "objc2-core-image 0.3.2", "objc2-core-text", "objc2-core-video", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", ] [[package]] @@ -2912,8 +4143,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ "bitflags 2.11.0", - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -2923,8 +4166,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ "bitflags 2.11.0", - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", ] [[package]] @@ -2935,7 +4178,7 @@ checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.11.0", "dispatch2", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -2946,19 +4189,31 @@ checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ "bitflags 2.11.0", "dispatch2", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", "objc2-io-surface", ] +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + [[package]] name = "objc2-core-image" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", ] [[package]] @@ -2967,8 +4222,8 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", ] [[package]] @@ -2978,7 +4233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", ] @@ -2990,7 +4245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", "objc2-io-surface", @@ -3011,6 +4266,18 @@ dependencies = [ "cc", ] +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + [[package]] name = "objc2-foundation" version = "0.3.2" @@ -3018,9 +4285,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.6.2", "libc", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -3031,7 +4298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -3041,10 +4308,22 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" dependencies = [ - "objc2", + "objc2 0.6.4", "objc2-core-foundation", ] +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-osa-kit" version = "0.3.2" @@ -3052,9 +4331,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" dependencies = [ "bitflags 2.11.0", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", ] [[package]] @@ -3064,9 +4356,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", ] [[package]] @@ -3076,7 +4368,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ "objc2-core-foundation", ] @@ -3087,17 +4388,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.11.0", - "block2", - "objc2", + "block2 0.6.2", + "objc2 0.6.4", "objc2-cloud-kit", - "objc2-core-data", + "objc2-core-data 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-core-image", + "objc2-core-image 0.3.2", "objc2-core-location", "objc2-core-text", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", "objc2-user-notifications", ] @@ -3108,10 +4409,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ "bitflags 2.11.0", - "block2", - "objc2", + "block2 0.6.2", + "objc2 0.6.4", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.3.2", ] [[package]] @@ -3121,11 +4422,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ "bitflags 2.11.0", - "block2", - "objc2", - "objc2-app-kit", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "objc2-javascript-core", "objc2-security", ] @@ -3139,6 +4440,29 @@ dependencies = [ "memchr", ] +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni 0.21.1", + "ndk 0.8.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -3151,6 +4475,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "open" version = "5.3.3" @@ -3163,12 +4493,210 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openhuman" +version = "0.53.4" +dependencies = [ + "aes-gcm", + "anyhow", + "arboard", + "argon2", + "async-imap", + "async-trait", + "axum", + "base64 0.22.1", + "chacha20poly1305", + "chrono", + "chrono-tz", + "clap", + "clap_complete", + "console", + "cpal", + "cron", + "dialoguer", + "directories 6.0.0", + "dirs 5.0.1", + "dotenvy", + "enigo", + "env_logger", + "fs2", + "futures", + "futures-util", + "hex", + "hmac 0.12.1", + "hostname", + "hound", + "html2md", + "iana-time-zone", + "image", + "lettre", + "log", + "mail-parser", + "nu-ansi-term 0.46.0", + "once_cell", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry_sdk", + "parking_lot", + "postgres", + "prometheus", + "prost", + "rand 0.9.2", + "rdev", + "regex", + "reqwest 0.12.28", + "ring", + "rusqlite", + "rustls", + "rustls-pki-types", + "schemars 1.2.1", + "sentry", + "serde", + "serde_json", + "serde_yaml", + "sha2 0.10.9", + "shellexpand", + "socketioxide", + "sysinfo", + "tar", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-tungstenite 0.24.0", + "tokio-util", + "toml 1.1.2+spec-1.1.0", + "tower", + "tracing", + "tracing-log", + "tracing-subscriber", + "unicode-segmentation", + "unicode-width", + "url", + "urlencoding", + "uuid", + "wait-timeout", + "webpki-roots 1.0.6", + "whisper-rs", + "xz2", + "zip 2.4.2", +] + +[[package]] +name = "openssl" +version = "0.10.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-sys" +version = "0.9.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", + "reqwest 0.12.28", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" +dependencies = [ + "http", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest 0.12.28", + "thiserror 2.0.18", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", + "tonic-prost", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.2", + "thiserror 2.0.18", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -3204,8 +4732,8 @@ dependencies = [ "android_system_properties", "log", "nix 0.30.1", - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", "objc2-ui-kit", "serde", "windows-sys 0.61.2", @@ -3217,14 +4745,20 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.6.4", + "objc2-foundation 0.3.2", "objc2-osa-kit", "serde", "serde_json", "thiserror 2.0.18", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pango" version = "0.18.3" @@ -3279,6 +4813,17 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "pathdiff" version = "0.2.3" @@ -3321,6 +4866,15 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + [[package]] name = "phf" version = "0.13.1" @@ -3469,6 +5023,15 @@ dependencies = [ "siphasher 1.0.2", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher 1.0.2", +] + [[package]] name = "phf_shared" version = "0.13.1" @@ -3478,6 +5041,26 @@ dependencies = [ "siphasher 1.0.2", ] +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -3539,6 +5122,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "polling" version = "3.11.0" @@ -3553,6 +5149,29 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -3568,6 +5187,50 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "postgres" +version = "0.19.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacf632d0554ff75f58183694f41dc8999c8a3a43a386994d0ec2d034f1dfbe1" +dependencies = [ + "bytes", + "fallible-iterator 0.2.0", + "futures-util", + "log", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56201207dac53e2f38e848e31b4b91616a6bb6e0c7205b77718994a7f49e70fc" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "hmac 0.13.0", + "md-5", + "memchr", + "rand 0.10.1", + "sha2 0.11.0", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc729a129e682e8d24170cd30ae1aa01b336b096cbb56df6d534ffec133d186" +dependencies = [ + "bytes", + "chrono", + "fallible-iterator 0.2.0", + "postgres-protocol", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -3676,6 +5339,55 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "memchr", + "parking_lot", + "thiserror 2.0.18", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pxfm" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.37.5" @@ -3759,6 +5471,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" + [[package]] name = "r-efi" version = "5.3.0" @@ -3806,6 +5524,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20 0.10.0", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -3863,6 +5592,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_hc" version = "0.2.0" @@ -3887,6 +5622,22 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rdev" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00552ca2dc2f93b84cd7b5581de49549411e4e41d89e1c691bcb93dc4be360c3" +dependencies = [ + "cocoa", + "core-foundation 0.7.0", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "lazy_static", + "libc", + "winapi", + "x11", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -3984,15 +5735,21 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", + "futures-util", + "h2", "http", "http-body", "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "js-sys", "log", + "mime_guess", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -4003,15 +5760,18 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams 0.4.2", "web-sys", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -4052,7 +5812,7 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", ] @@ -4077,7 +5837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ "bitflags 2.11.0", - "fallible-iterator", + "fallible-iterator 0.3.0", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", @@ -4172,9 +5932,9 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", + "core-foundation 0.10.1", + "core-foundation-sys 0.8.7", + "jni 0.21.1", "log", "once_cell", "rustls", @@ -4287,8 +6047,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags 2.11.0", - "core-foundation", - "core-foundation-sys", + "core-foundation 0.10.1", + "core-foundation-sys 0.8.7", "libc", "security-framework-sys", ] @@ -4299,7 +6059,7 @@ version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.7", "libc", ] @@ -4340,6 +6100,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "self_cell" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" + [[package]] name = "semver" version = "1.0.27" @@ -4514,6 +6280,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -4586,6 +6363,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.13.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serialize-to-javascript" version = "0.1.2" @@ -4634,8 +6424,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -4651,8 +6441,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shellexpand" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" +dependencies = [ + "dirs 6.0.0", ] [[package]] @@ -4711,6 +6536,56 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "socketioxide" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "929e1bc0629c6c8ceaa39473082aa2df35a2a5f0c300382912047bd5dccb9740" +dependencies = [ + "bytes", + "engineioxide", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "matchit", + "pin-project-lite", + "rustversion", + "serde", + "socketioxide-core", + "socketioxide-parser-common", + "thiserror 1.0.69", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "socketioxide-core" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20fbe5455c862962f547bac834bcc6db8659a7033934b9c45c6e1cfb4f9dc178" +dependencies = [ + "bytes", + "engineioxide", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "socketioxide-parser-common" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "554757f11f7b0944334fc00765523443c39a05fcd7be69aaaffbda06fbc4cef7" +dependencies = [ + "bytes", + "itoa", + "serde", + "serde_json", + "socketioxide-core", +] + [[package]] name = "socks" version = "0.3.4" @@ -4730,12 +6605,12 @@ checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "bytemuck", "js-sys", - "ndk", - "objc2", + "ndk 0.9.0", + "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", "raw-window-handle", "redox_syscall 0.5.18", "tracing", @@ -4776,6 +6651,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stop-token" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af91f480ee899ab2d9f8435bfdfc14d08a5754bd9d3fef1f1a1c23336aad6c8b" +dependencies = [ + "async-channel 1.9.0", + "cfg-if", + "futures-core", + "pin-project-lite", +] + [[package]] name = "string_cache" version = "0.8.9" @@ -4825,6 +6712,17 @@ dependencies = [ "quote", ] +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -4890,6 +6788,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "sysinfo" +version = "0.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", + "memchr", + "ntapi", + "windows 0.57.0", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -4910,31 +6821,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" dependencies = [ "bitflags 2.11.0", - "block2", - "core-foundation", - "core-graphics", + "block2 0.6.2", + "core-foundation 0.10.1", + "core-graphics 0.25.0", "crossbeam-channel", "dispatch2", "dlopen2", "dpi", "gdkwayland-sys", "gtk", - "jni", + "jni 0.21.1", "libc", "log", - "ndk", + "ndk 0.9.0", "ndk-context", - "ndk-sys", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", "once_cell", "parking_lot", "raw-window-handle", "tao-macros", "unicode-segmentation", "url", - "windows", + "windows 0.61.3", "windows-core 0.61.2", "windows-version", ] @@ -4975,7 +6886,7 @@ dependencies = [ "bytes", "cookie", "data-url", - "dirs", + "dirs 6.0.0", "dunce", "embed_plist", "getrandom 0.3.4", @@ -4983,14 +6894,14 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni", + "jni 0.21.1", "libc", "log", "mime", "muda", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "percent-encoding", @@ -5015,7 +6926,7 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.61.3", ] [[package]] @@ -5024,7 +6935,7 @@ version = "2.5.6" dependencies = [ "anyhow", "cargo_toml", - "dirs", + "dirs 6.0.0", "glob", "heck 0.5.0", "json-patch", @@ -5046,13 +6957,13 @@ dependencies = [ "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "syn 2.0.117", "tauri-utils", "thiserror 2.0.18", @@ -5147,8 +7058,8 @@ source = "git+https://github.com/tauri-apps/plugins-workspace?rev=c6561ab6b4f9e7 dependencies = [ "dunce", "glob", - "objc2-app-kit", - "objc2-foundation", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", "open", "schemars 1.2.1", "serde", @@ -5157,7 +7068,7 @@ dependencies = [ "tauri-plugin", "thiserror 2.0.18", "url", - "windows", + "windows 0.61.3", "zbus", ] @@ -5168,7 +7079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af" dependencies = [ "base64 0.22.1", - "dirs", + "dirs 6.0.0", "flate2", "futures-util", "http", @@ -5202,8 +7113,8 @@ dependencies = [ "dpi", "gtk", "http", - "jni", - "objc2", + "jni 0.21.1", + "objc2 0.6.4", "objc2-ui-kit", "raw-window-handle", "serde", @@ -5211,7 +7122,7 @@ dependencies = [ "tauri-utils", "thiserror 2.0.18", "url", - "windows", + "windows 0.61.3", ] [[package]] @@ -5222,23 +7133,23 @@ dependencies = [ "cef", "cef-dll-sys", "dioxus-debug-cell", - "dirs", + "dirs 6.0.0", "gtk", "html5ever 0.29.1", "http", "kuchikiki", "log", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", "raw-window-handle", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tauri-runtime", "tauri-utils", "url", - "windows", + "windows 0.61.3", "x11-dl", ] @@ -5248,10 +7159,10 @@ version = "2.10.1" dependencies = [ "gtk", "http", - "jni", + "jni 0.21.1", "log", - "objc2", - "objc2-app-kit", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-web-kit", "once_cell", "percent-encoding", @@ -5263,7 +7174,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", "wry", ] @@ -5321,7 +7232,7 @@ checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", "thiserror 2.0.18", - "windows", + "windows 0.61.3", "windows-version", ] @@ -5399,6 +7310,29 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "time" version = "0.3.47" @@ -5473,6 +7407,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5491,6 +7426,42 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd8df5ef180f6364759a6f00f7aadda4fbbac86cdee37480826a6ff9f3574ce" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf 0.13.1", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.10.1", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -5501,6 +7472,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -5509,8 +7492,24 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", + "rustls", + "rustls-pki-types", "tokio", - "tungstenite", + "tokio-rustls", + "tungstenite 0.24.0", + "webpki-roots 0.26.11", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.29.0", ] [[package]] @@ -5522,6 +7521,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", + "futures-util", "pin-project-lite", "tokio", ] @@ -5553,6 +7553,21 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.0", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -5631,6 +7646,38 @@ version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +[[package]] +name = "tonic" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "http", + "http-body", + "http-body-util", + "percent-encoding", + "pin-project", + "sync_wrapper", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-prost" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.3" @@ -5708,12 +7755,30 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ + "matchers", + "nu-ansi-term 0.50.3", + "once_cell", + "regex-automata", + "sharded-slab", + "thread_local", + "tracing", "tracing-core", ] @@ -5724,16 +7789,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" dependencies = [ "crossbeam-channel", - "dirs", + "dirs 6.0.0", "libappindicator", "muda", - "objc2", - "objc2-app-kit", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation", + "objc2-foundation 0.3.2", "once_cell", - "png", + "png 0.17.16", "serde", "thiserror 2.0.18", "windows-sys 0.60.2", @@ -5758,11 +7823,29 @@ dependencies = [ "httparse", "log", "rand 0.8.5", + "rustls", + "rustls-pki-types", "sha1", "thiserror 1.0.69", "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.18", +] + [[package]] name = "typeid" version = "1.0.3" @@ -5836,12 +7919,39 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "unicode-segmentation" version = "1.13.2" @@ -5866,6 +7976,22 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -5890,7 +8016,7 @@ dependencies = [ "socks", "ureq-proto", "utf8-zero", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -5918,6 +8044,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "urlpattern" version = "0.3.0" @@ -6010,6 +8142,15 @@ dependencies = [ "libc", ] +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -6041,6 +8182,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -6059,6 +8209,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + [[package]] name = "wasm-bindgen" version = "0.2.115" @@ -6136,6 +8295,19 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasm-streams" version = "0.5.0" @@ -6246,6 +8418,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + [[package]] name = "webpki-roots" version = "1.0.6" @@ -6263,10 +8444,10 @@ checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", + "windows 0.61.3", "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", ] [[package]] @@ -6287,10 +8468,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ "thiserror 2.0.18", - "windows", + "windows 0.61.3", "windows-core 0.61.2", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "whisper-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2088172d00f936c348d6a72f488dc2660ab3f507263a195df308a3c2383229f6" +dependencies = [ + "whisper-rs-sys", +] + +[[package]] +name = "whisper-rs-sys" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6986c0fe081241d391f09b9a071fbcbb59720c3563628c3c829057cf69f2a56f" +dependencies = [ + "bindgen", + "cfg-if", + "cmake", + "fs_extra", + "semver", +] + +[[package]] +name = "whoami" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5b12f9df4f978d2cfdb1bd3bac52433f44393342d7ee9c25f5a1c14c0f45d" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6328,15 +8550,45 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2", - "objc2-app-kit", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "raw-window-handle", "windows-sys 0.59.0", "windows-version", ] +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.61.3" @@ -6359,14 +8611,49 @@ dependencies = [ "windows-core 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", @@ -6378,8 +8665,8 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.2.1", "windows-result 0.4.1", "windows-strings 0.5.1", @@ -6396,6 +8683,28 @@ dependencies = [ "windows-threading", ] +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -6407,6 +8716,28 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -6451,6 +8782,24 @@ dependencies = [ "windows-strings 0.4.2", ] +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -6469,6 +8818,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -6940,29 +9299,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" dependencies = [ "base64 0.22.1", - "block2", + "block2 0.6.2", "cookie", "crossbeam-channel", - "dirs", + "dirs 6.0.0", "dom_query", "dpi", "dunce", "gtk", "http", "javascriptcore-rs", - "jni", + "jni 0.21.1", "libc", - "ndk", - "objc2", - "objc2-app-kit", + "ndk 0.9.0", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", "thiserror 2.0.18", @@ -6970,11 +9329,21 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", + "windows 0.61.3", "windows-core 0.61.2", "windows-version", ] +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -7013,12 +9382,43 @@ dependencies = [ "rustix", ] +[[package]] +name = "xkbcommon" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" +dependencies = [ + "libc", + "memmap2", + "xkeysym", +] + [[package]] name = "xkeysym" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +[[package]] +name = "xml5ever" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69" +dependencies = [ + "log", + "mac", + "markup5ever 0.12.1", +] + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yoke" version = "0.8.1" @@ -7058,7 +9458,7 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener", + "event-listener 5.4.1", "futures-core", "futures-lite", "hex", @@ -7230,6 +9630,21 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + [[package]] name = "zvariant" version = "5.10.0" diff --git a/app/src-tauri/Cargo.toml b/app/src-tauri/Cargo.toml index 680e226d2..463c84de9 100644 --- a/app/src-tauri/Cargo.toml +++ b/app/src-tauri/Cargo.toml @@ -80,15 +80,6 @@ hex = "0.4" # "No provider set" the first time `tauri dev` proxies a request. We install # the ring provider at startup in `lib.rs::run()`. rustls = { version = "0.23", default-features = false, features = ["ring"] } -semver = "1" -# Auto-update archive extraction. GitHub release assets ship as -# `openhuman-core--.tar.gz` on Unix and `….zip` -# on Windows; the inner binary is `openhuman-core` (or `.exe`) with no -# wrapping directory. See `core_update.rs::extract_archive`. -flate2 = "1" -tar = "0.4" -zip = { version = "2", default-features = false, features = ["deflate"] } - log = "0.4" env_logger = "0.11" @@ -114,6 +105,14 @@ async-trait = "0.1" tauri-runtime-cef = { path = "vendor/tauri-cef/crates/tauri-runtime-cef" } cef = { version = "=146.4.1", default-features = false } +# Core domain logic, embedded in-process so the core's HTTP/JSON-RPC server +# runs as a tokio task inside the Tauri host. Avoids the orphan-sidecar class +# of bugs (PR #1061: Cmd+Q leaving `openhuman-core` and CEF helpers behind) +# by tying the core's lifetime to the GUI process. The existing port-7788 +# probe in `core_process::ensure_running` still attaches to a running +# `openhuman-core run` harness when one is already listening. +openhuman_core = { path = "../..", package = "openhuman", default-features = false } + [target.'cfg(unix)'.dependencies] nix = { version = "0.29", default-features = false, features = ["signal"] } diff --git a/app/src-tauri/src/core_process.rs b/app/src-tauri/src/core_process.rs index 782f4e6ee..bc7edf779 100644 --- a/app/src-tauri/src/core_process.rs +++ b/app/src-tauri/src/core_process.rs @@ -1,53 +1,20 @@ -use std::io::IsTerminal; -use std::path::PathBuf; +//! In-process core lifecycle. +//! +//! The core's HTTP/JSON-RPC server runs as a tokio task inside the Tauri host +//! so its lifetime is tied to the GUI process — there is no sidecar to leak +//! on Cmd+Q. If something is already listening on the configured port (e.g. +//! a manual `openhuman-core run` harness for debugging), `ensure_running` +//! attaches to it instead of spawning a duplicate listener. + use std::sync::Arc; use std::sync::LazyLock; use parking_lot::RwLock; use tokio::net::TcpStream; -use tokio::process::{Child, Command}; use tokio::sync::Mutex; use tokio::task::JoinHandle; use tokio::time::{timeout, Duration}; -/// Propagate ANSI color hints to the spawned core child. -/// -/// Core's tracing formatter auto-detects color via `stderr.is_terminal()`, -/// but when core runs as a grandchild under `yarn tauri dev` the inherited -/// stderr may not register as a TTY even though the ultimate terminal -/// supports ANSI. If the Tauri process itself is attached to a TTY we -/// forward `FORCE_COLOR=1` so core emits colored log lines; `NO_COLOR` -/// (user opt-out) always wins and short-circuits the propagation. -fn apply_core_color_env(cmd: &mut Command) { - if std::env::var_os("NO_COLOR").is_some() { - return; - } - if std::io::stderr().is_terminal() { - cmd.env("FORCE_COLOR", "1"); - } -} - -/// Hide the console window that Windows would otherwise allocate for the -/// core sidecar. The core binary is a console-subsystem executable so that -/// `openhuman core run` in a terminal behaves normally, but when the GUI -/// shell spawns it as a child a stray conhost window pops up on top of the -/// app. `CREATE_NO_WINDOW` suppresses that while leaving stdout/stderr -/// piping intact for our log forwarding. -#[cfg(windows)] -fn apply_core_no_window(cmd: &mut Command) { - const CREATE_NO_WINDOW: u32 = 0x0800_0000; - cmd.creation_flags(CREATE_NO_WINDOW); -} - -#[cfg(not(windows))] -fn apply_core_no_window(_cmd: &mut Command) {} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum CoreRunMode { - InProcess, - ChildProcess, -} - /// Generate a 256-bit cryptographically-random bearer token as a hex string. /// /// Uses the same encoding as `openhuman_core::core::auth::generate_token` @@ -68,41 +35,35 @@ pub fn current_rpc_token() -> Option { #[derive(Clone)] pub struct CoreProcessHandle { - child: Arc>>, task: Arc>>>, restart_lock: Arc>, port: u16, - core_bin: Option, - /// Override path set by the auto-updater after staging a new binary. - core_bin_override: Arc>>, - run_mode: CoreRunMode, - /// Bearer token passed to the core via `OPENHUMAN_CORE_TOKEN` and returned - /// to the frontend so every RPC request can include `Authorization: Bearer`. + /// Bearer token the embedded server validates on every inbound request. + /// Passed to the embedded server through the `OPENHUMAN_CORE_TOKEN` + /// process env var (set in `ensure_running` before spawn) and exposed to + /// the frontend via the `core_rpc_token` Tauri command so every RPC call + /// can include `Authorization: Bearer`. rpc_token: Arc, } impl CoreProcessHandle { - pub fn new(port: u16, core_bin: Option, run_mode: CoreRunMode) -> Self { + pub fn new(port: u16) -> Self { + // CURRENT_RPC_TOKEN is intentionally NOT set here. It is published by + // ensure_running() only after the embedded server has been spawned + // with OPENHUMAN_CORE_TOKEN in scope. Setting it here would advertise + // a token that an existing process listening on the port (the + // harness-attach fast-path) has never seen, causing 401s on every + // authenticated call. let rpc_token = generate_rpc_token(); - // CURRENT_RPC_TOKEN is intentionally NOT set here. It is published by - // ensure_running() only after the child process that received - // OPENHUMAN_CORE_TOKEN has been successfully spawned. Setting it here - // would advertise a token that the running core (which may be a stale - // process the handle did not spawn) has never seen, causing 401s on - // every subsequent authenticated call. Self { - child: Arc::new(Mutex::new(None)), task: Arc::new(Mutex::new(None)), restart_lock: Arc::new(Mutex::new(())), port, - core_bin, - core_bin_override: Arc::new(Mutex::new(None)), - run_mode, rpc_token: Arc::new(rpc_token), } } - /// The bearer token the core process uses to authenticate inbound RPC requests. + /// The bearer token the embedded core validates on inbound RPC requests. pub fn rpc_token(&self) -> &str { &self.rpc_token } @@ -115,28 +76,6 @@ impl CoreProcessHandle { self.port } - /// Replace the core binary path so that the next `ensure_running()` launches - /// the new binary instead of the original one captured at construction time. - pub async fn set_core_bin(&self, new_bin: PathBuf) { - // We store it via a second field; but since core_bin is not behind a lock, - // we work around this by swapping the entire handle's notion of what to launch. - // For now, mutate through an interior-mutable wrapper. - log::info!( - "[core] set_core_bin: updating core binary path to {}", - new_bin.display() - ); - *self.core_bin_override.lock().await = Some(new_bin); - } - - /// Resolve which binary to launch: override (set by `set_core_bin`) > original. - async fn effective_core_bin(&self) -> Option { - let override_guard = self.core_bin_override.lock().await; - if let Some(ref path) = *override_guard { - return Some(path.clone()); - } - self.core_bin.clone() - } - /// Acquire the restart lock to serialize overlapping restart requests. pub async fn restart_lock(&self) -> tokio::sync::MutexGuard<'_, ()> { self.restart_lock.lock().await @@ -160,95 +99,37 @@ impl CoreProcessHandle { self.rpc_url() ); log::warn!( - "[core] reusing port {} — if channel/Telegram behavior mismatches the app, another stale `openhuman` core may be attached; check [core-update] logs for version skew.", + "[core] reusing port {} — another `openhuman-core` instance is already listening; this Tauri host will not spawn an embedded server. Authenticated Tauri-side calls will 401 unless the listener was started with this process's OPENHUMAN_CORE_TOKEN.", self.port ); return Ok(()); } - let effective_bin = self.effective_core_bin().await; - - match self.run_mode { - CoreRunMode::InProcess => { - log::warn!( - "[core] in-process core mode is unavailable in host-only build; falling back to child process" - ); - let mut guard = self.child.lock().await; - if guard.is_none() { - let mut cmd = if let Some(core_bin) = &effective_bin { - let mut cmd = Command::new(core_bin); - if is_current_exe_path(core_bin) { - cmd.arg("core"); - } - cmd.arg("run").arg("--port").arg(self.port.to_string()); - cmd + { + let mut guard = self.task.lock().await; + if guard.is_none() { + let port = self.port; + // Set OPENHUMAN_CORE_TOKEN as a process-global env var before + // spawning the embedded server. Same-process tokio task reads + // the same env, matching what a child sidecar would have + // received via Command::env. + std::env::set_var("OPENHUMAN_CORE_TOKEN", self.rpc_token.as_str()); + log::info!("[core] spawning embedded in-process core server on port {port}"); + let task = tokio::spawn(async move { + if let Err(e) = + openhuman_core::core::jsonrpc::run_server_embedded(None, Some(port), true) + .await + { + log::error!("[core] embedded core server exited with error: {e}"); } else { - let exe = std::env::current_exe() - .map_err(|e| format!("failed to resolve current executable: {e}"))?; - let mut cmd = Command::new(exe); - cmd.arg("core") - .arg("run") - .arg("--port") - .arg(self.port.to_string()); - cmd - }; - apply_core_color_env(&mut cmd); - apply_core_no_window(&mut cmd); - cmd.env("OPENHUMAN_CORE_TOKEN", self.rpc_token.as_str()); - let child = cmd - .spawn() - .map_err(|e| format!("failed to spawn core process: {e}"))?; - *guard = Some(child); - // Publish only after the child that holds OPENHUMAN_CORE_TOKEN - // has been spawned successfully. - *CURRENT_RPC_TOKEN.write() = Some(self.rpc_token.to_string()); - log::debug!("[auth] CURRENT_RPC_TOKEN set after in-process spawn"); - } - } - CoreRunMode::ChildProcess => { - let mut guard = self.child.lock().await; - if guard.is_none() { - let mut cmd = if let Some(core_bin) = &effective_bin { - let mut cmd = Command::new(core_bin); - if is_current_exe_path(core_bin) { - // Safety: if core_bin resolves to this GUI executable, force the - // explicit subcommand path so we don't accidentally relaunch clients. - cmd.arg("core"); - } - cmd.arg("run").arg("--port").arg(self.port.to_string()); - log::info!( - "[core] spawning dedicated core binary: {:?} run --port {}", - cmd.as_std().get_program(), - self.port - ); - cmd - } else { - let exe = std::env::current_exe() - .map_err(|e| format!("failed to resolve current executable: {e}"))?; - let mut cmd = Command::new(exe); - cmd.arg("core") - .arg("run") - .arg("--port") - .arg(self.port.to_string()); - log::warn!( - "[core] dedicated core binary not found; falling back to self subcommand" - ); - cmd - }; - - apply_core_color_env(&mut cmd); - apply_core_no_window(&mut cmd); - cmd.env("OPENHUMAN_CORE_TOKEN", self.rpc_token.as_str()); - let child = cmd - .spawn() - .map_err(|e| format!("failed to spawn core process: {e}"))?; - - *guard = Some(child); - // Publish only after the child that holds OPENHUMAN_CORE_TOKEN - // has been spawned successfully. - *CURRENT_RPC_TOKEN.write() = Some(self.rpc_token.to_string()); - log::debug!("[auth] CURRENT_RPC_TOKEN set after child process spawn"); - } + log::info!("[core] embedded core server exited cleanly"); + } + }); + *guard = Some(task); + // Publish only after the embedded server has been spawned + // with OPENHUMAN_CORE_TOKEN in scope. + *CURRENT_RPC_TOKEN.write() = Some(self.rpc_token.to_string()); + log::debug!("[auth] CURRENT_RPC_TOKEN set after embedded spawn"); } } @@ -258,272 +139,101 @@ impl CoreProcessHandle { return Ok(()); } - match self.run_mode { - CoreRunMode::InProcess => { - let mut guard = self.task.lock().await; - if let Some(task) = guard.as_ref() { - if task.is_finished() { - let task = guard.take().expect("checked is_some"); - drop(guard); - match task.await { - Ok(_) => { - return Err( - "in-process core server exited before becoming ready" - .to_string(), - ) - } - Err(err) => { - return Err(format!( - "in-process core server task failed before ready: {err}" - )) - } - } + let mut guard = self.task.lock().await; + if let Some(task) = guard.as_ref() { + if task.is_finished() { + let task = guard.take().expect("checked is_some"); + drop(guard); + return match task.await { + Ok(_) => { + Err("in-process core server exited before becoming ready".to_string()) } - } - } - CoreRunMode::ChildProcess => { - let mut guard = self.child.lock().await; - if let Some(child) = guard.as_mut() { - match child.try_wait() { - Ok(Some(status)) => { - return Err(format!("core process exited before ready: {status}")); - } - Ok(None) => {} - Err(e) => { - return Err(format!("failed checking core process status: {e}")); - } - } - } + Err(err) => Err(format!( + "in-process core server task failed before ready: {err}" + )), + }; } } - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + tokio::time::sleep(Duration::from_millis(100)).await; } Err("core process did not become ready".to_string()) } - /// Restart the core process to pick up updated macOS permission grants. + /// Restart the embedded core to pick up updated macOS permission grants. /// - /// macOS caches permission state per-process; the running sidecar never sees - /// a newly granted permission until it restarts. This method shuts down the - /// current child, waits until the RPC port is free (so `ensure_running` does not - /// fast-return while the old listener is still bound), then spawns a fresh instance. - /// - /// If another process is listening on the core port (e.g. manual `openhuman core run`), - /// shutdown does not stop it — we time out and return an error instead of a false success. + /// macOS caches permission state per-process; restarting forces a fresh + /// read. If something else is bound to the port (e.g. a manual + /// `openhuman-core run` harness) we surface that instead of looping. /// /// Issue: pub async fn restart(&self) -> Result<(), String> { - log::info!("[core] restarting core process for permission refresh"); + log::info!("[core] restarting embedded core server for permission refresh"); - let had_managed_child = { - let guard = self.child.lock().await; + let had_managed_task = { + let guard = self.task.lock().await; guard.is_some() }; - log::debug!( - "[core] restart: had_managed_child={} before shutdown", - had_managed_child - ); self.shutdown().await; - log::debug!( - "[core] restart: shutdown complete, checking port {}", - self.port - ); - // If we never spawned the sidecar (something else was already listening), we cannot free - // the port — fail fast with a clear message instead of polling for 8s. - if !had_managed_child && self.is_rpc_port_open().await { + if !had_managed_task && self.is_rpc_port_open().await { log::error!( - "[core] restart: no child to stop but port {} is open — another process owns it", + "[core] restart: nothing to stop but port {} is in use — another process owns it", self.port ); return Err(format!( - "Core RPC port {} is already in use by another process (OpenHuman did not start it). Quit any `openhuman core run` in a terminal or free the port, then relaunch the app. You can also set OPENHUMAN_CORE_PORT to a different port.", + "Core RPC port {} is already in use by another process (OpenHuman did not start it). Quit any `openhuman-core run` in a terminal or set OPENHUMAN_CORE_PORT to a different port, then relaunch the app.", self.port )); } - // After kill+wait on our child, the port should close; poll briefly in case the OS is slow - // to release the socket. const POLL_MS: u64 = 50; const MAX_WAIT_MS: u64 = 10_000; let mut waited_ms: u64 = 0; while self.is_rpc_port_open().await { if waited_ms >= MAX_WAIT_MS { - log::error!( - "[core] restart: port {} still in use after {}ms (had_managed_child={})", - self.port, - MAX_WAIT_MS, - had_managed_child - ); return Err(format!( - "Core RPC port {} did not become free after stopping the sidecar. Quit any other process using this port (e.g. `openhuman core run`) or change OPENHUMAN_CORE_PORT.", + "Core RPC port {} did not become free after stopping the embedded server.", self.port )); } - tokio::time::sleep(std::time::Duration::from_millis(POLL_MS)).await; + tokio::time::sleep(Duration::from_millis(POLL_MS)).await; waited_ms += POLL_MS; } - log::debug!("[core] restart: port free, calling ensure_running"); let result = self.ensure_running().await; match &result { - Ok(()) => log::info!("[core] restart: core process ready after restart"), - Err(e) => log::error!("[core] restart: failed to restart core process: {e}"), + Ok(()) => log::info!("[core] restart: embedded core ready after restart"), + Err(e) => log::error!("[core] restart: failed to restart embedded core: {e}"), } result } - /// Stop the core process this handle spawned (child or in-process task). Safe to call if - /// nothing was spawned or core was already external. - /// - /// On Unix, sends SIGTERM first so the core process can run its graceful - /// shutdown hooks (e.g. stopping the autocomplete engine and its Swift - /// overlay helper). Falls back to SIGKILL after a timeout. - pub async fn shutdown(&self) { - let mut child_guard = self.child.lock().await; - if let Some(mut child) = child_guard.take() { - log::info!("[core] terminating child core process on app shutdown"); - - let exited = self.try_graceful_terminate(&child).await; - - if !exited { - log::info!("[core] graceful shutdown timed out, sending SIGKILL"); - if let Err(e) = child.kill().await { - log::warn!("[core] failed to kill child core process: {e}"); - } - } - - // Wait for the process to exit so the RPC listen socket is released before restart - // checks the port (otherwise we can spuriously hit "port still in use"). - match timeout(Duration::from_secs(12), child.wait()).await { - Ok(Ok(status)) => { - log::debug!("[core] child core process reaped after shutdown: {status}"); - } - Ok(Err(e)) => { - log::warn!("[core] wait on child core process after shutdown: {e}"); - } - Err(_) => { - log::warn!("[core] timed out waiting for child core process to exit (12s)"); - } - } - } + /// Lock the task slot, take its handle if any, and abort it. Shared by + /// `shutdown` (cleanup-on-drop semantics) and `send_terminate_signal` + /// (cooperative early teardown from `RunEvent::ExitRequested`). + async fn abort_task(&self, log_context: &str) { let mut task_guard = self.task.lock().await; if let Some(task) = task_guard.take() { + log::info!("[core] aborting embedded core server task{log_context}"); task.abort(); } } - /// Send SIGTERM (Unix) / TerminateProcess (Windows) to the spawned - /// child without waiting for it to exit. Returns immediately. + /// Stop the embedded server task. Safe to call when nothing is running. + pub async fn shutdown(&self) { + self.abort_task("").await; + } + + /// Synchronous-friendly shutdown for `RunEvent::ExitRequested`. /// - /// Used by the Tauri `RunEvent::ExitRequested` path so app shutdown - /// doesn't block on the core sidecar: the child receives the signal, - /// runs its own graceful shutdown hooks, and is reaped by the kernel - /// after the parent process exits. Blocking on `child.wait()` from the - /// main thread starves CEF's UI message loop (RunEvent is delivered on - /// the same thread) and on macOS that races the `browser_count == 0` - /// CHECK in `cef::shutdown`, panicking the app on Cmd+Q. + /// Aborts the embedded server task so any background tokio tasks the + /// server spawned stop driving I/O before CEF's teardown runs. Cheap + /// and non-blocking on the UI thread — `JoinHandle::abort` returns + /// immediately. pub async fn send_terminate_signal(&self) { - let mut child_guard = self.child.lock().await; - let Some(child) = child_guard.as_mut() else { - return; - }; - - #[cfg(unix)] - { - use nix::sys::signal::{self, Signal}; - use nix::unistd::Pid; - let _ = child; - if let Some(pid) = child_guard.as_ref().and_then(|c| c.id()) { - match signal::kill(Pid::from_raw(pid as i32), Signal::SIGTERM) { - Ok(()) => log::info!("[core] SIGTERM sent (non-blocking) pid={pid}"), - Err(e) => log::warn!("[core] SIGTERM (non-blocking) failed: {e}"), - } - } - } - - #[cfg(windows)] - { - match child.start_kill() { - Ok(()) => log::info!("[core] start_kill issued (non-blocking)"), - Err(e) => log::warn!("[core] start_kill (non-blocking) failed: {e}"), - } - } - } - - /// Send SIGTERM to the child and wait up to 5 seconds for it to exit. - /// Returns `true` if the process exited gracefully, `false` if it's still - /// alive (caller should escalate to SIGKILL). - async fn try_graceful_terminate(&self, child: &Child) -> bool { - #[cfg(unix)] - { - use nix::sys::signal::{self, Signal}; - use nix::unistd::Pid; - - let Some(pid) = child.id() else { - log::debug!("[core] child has no PID (already exited?)"); - return true; - }; - - log::info!("[core] sending SIGTERM to core process (pid={pid})"); - if let Err(e) = signal::kill(Pid::from_raw(pid as i32), Signal::SIGTERM) { - log::warn!("[core] failed to send SIGTERM: {e}"); - return false; - } - - // Poll for exit for up to 5 seconds. - const GRACE_PERIOD: Duration = Duration::from_secs(5); - const POLL_INTERVAL: Duration = Duration::from_millis(100); - let start = tokio::time::Instant::now(); - - while start.elapsed() < GRACE_PERIOD { - // Check if process is still alive (signal 0 = existence check). - match signal::kill(Pid::from_raw(pid as i32), None) { - Err(nix::errno::Errno::ESRCH) => { - log::info!( - "[core] core process exited gracefully after SIGTERM ({}ms)", - start.elapsed().as_millis() - ); - return true; - } - _ => {} - } - tokio::time::sleep(POLL_INTERVAL).await; - } - - log::warn!( - "[core] core process still alive after {}s grace period", - GRACE_PERIOD.as_secs() - ); - false - } - - #[cfg(not(unix))] - { - // On non-Unix platforms, there is no SIGTERM equivalent; the caller - // will use `child.kill()` directly. - let _ = child; - false - } - } -} - -fn is_current_exe_path(candidate: &std::path::Path) -> bool { - let Ok(current) = std::env::current_exe() else { - return false; - }; - same_executable_path(candidate, ¤t) -} - -fn same_executable_path(a: &std::path::Path, b: &std::path::Path) -> bool { - if a == b { - return true; - } - match (std::fs::canonicalize(a), std::fs::canonicalize(b)) { - (Ok(a_real), Ok(b_real)) => a_real == b_real, - _ => false, + self.abort_task(" on app shutdown").await; } } @@ -534,166 +244,6 @@ pub fn default_core_port() -> u16 { .unwrap_or(7788) } -pub fn default_core_run_mode(_daemon_mode: bool) -> CoreRunMode { - if let Ok(value) = std::env::var("OPENHUMAN_CORE_RUN_MODE") { - let normalized = value.trim().to_ascii_lowercase(); - if matches!(normalized.as_str(), "inprocess" | "in-process" | "internal") { - return CoreRunMode::InProcess; - } - if matches!( - normalized.as_str(), - "child" | "process" | "external" | "sidecar" - ) { - return CoreRunMode::ChildProcess; - } - } - - // Default to a dedicated core process so app and core lifecycles are separated. - CoreRunMode::ChildProcess -} - -pub fn default_core_bin() -> Option { - if let Ok(path) = std::env::var("OPENHUMAN_CORE_BIN") { - let candidate = PathBuf::from(path); - if candidate.exists() { - log::info!( - "[core] default_core_bin: using OPENHUMAN_CORE_BIN override {}", - candidate.display() - ); - return Some(candidate); - } - log::warn!( - "[core] default_core_bin: OPENHUMAN_CORE_BIN override does not exist: {}", - candidate.display() - ); - } - - #[cfg(target_os = "linux")] - { - let packaged_candidates = [ - PathBuf::from("/usr/bin/openhuman-core"), - PathBuf::from("/usr/lib/OpenHuman/openhuman-core"), - ]; - for candidate in packaged_candidates { - if candidate.exists() { - log::info!( - "[core] default_core_bin: using packaged linux core binary {}", - candidate.display() - ); - return Some(candidate); - } - } - } - - // Dev: prefer a staged sidecar under src-tauri/binaries, then use the same search as - // release (next to the .app, Resources/, etc.). Previously we returned None here when the - // folder was empty, which forced `core run` on the GUI binary — a different TCC identity than - // `openhuman-core-*` and misleading "still denied" after granting the sidecar name. - #[cfg(debug_assertions)] - { - let binaries_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("binaries"); - if let Ok(entries) = std::fs::read_dir(&binaries_dir) { - for entry in entries.flatten() { - let path = entry.path(); - if !path.is_file() { - continue; - } - let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else { - continue; - }; - #[cfg(windows)] - let matches = - file_name.starts_with("openhuman-core-") && file_name.ends_with(".exe"); - #[cfg(not(windows))] - let matches = file_name.starts_with("openhuman-core-"); - if matches { - return Some(path); - } - } - } - } - - let exe = std::env::current_exe().ok()?; - let exe_dir = exe.parent()?; - - #[cfg(windows)] - let standalone = exe_dir.join("openhuman-core.exe"); - #[cfg(not(windows))] - let standalone = exe_dir.join("openhuman-core"); - - if standalone.exists() && !same_executable_path(&standalone, &exe) { - log::info!( - "[core] default_core_bin: found standalone sibling binary {}", - standalone.display() - ); - return Some(standalone); - } - - #[cfg(windows)] - let legacy_standalone = exe_dir.join("openhuman-core.exe"); - #[cfg(not(windows))] - let legacy_standalone = exe_dir.join("openhuman-core"); - - if legacy_standalone.exists() && !same_executable_path(&legacy_standalone, &exe) { - log::info!( - "[core] default_core_bin: found legacy standalone binary {}", - legacy_standalone.display() - ); - return Some(legacy_standalone); - } - - // Sidecar layout: bundle.externalBin("binaries/openhuman-core") is emitted as - // openhuman-core-(.exe) under app resources. - let search_dirs = { - let dirs = vec![exe_dir.to_path_buf()]; - #[cfg(target_os = "macos")] - { - let mut dirs = dirs; - if let Some(resources_dir) = exe_dir.parent().map(|p| p.join("Resources")) { - dirs.push(resources_dir); - } - dirs - } - #[cfg(not(target_os = "macos"))] - { - dirs - } - }; - - for dir in search_dirs { - let Ok(entries) = std::fs::read_dir(&dir) else { - continue; - }; - for entry in entries.flatten() { - let path = entry.path(); - if !path.is_file() { - continue; - } - let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else { - continue; - }; - - #[cfg(windows)] - let matches = (file_name.starts_with("openhuman-core-") && file_name.ends_with(".exe")) - || (file_name.starts_with("openhuman-core-") && file_name.ends_with(".exe")); - #[cfg(not(windows))] - let matches = file_name.starts_with("openhuman-core-") - || file_name.starts_with("openhuman-core-"); - - if matches && !same_executable_path(&path, &exe) { - log::info!( - "[core] default_core_bin: found bundled sidecar {}", - path.display() - ); - return Some(path); - } - } - } - - log::warn!("[core] default_core_bin: no dedicated core binary found"); - None -} - #[cfg(test)] #[path = "core_process_tests.rs"] mod tests; diff --git a/app/src-tauri/src/core_process_tests.rs b/app/src-tauri/src/core_process_tests.rs index 18b54a1aa..6a7f6b6f1 100644 --- a/app/src-tauri/src/core_process_tests.rs +++ b/app/src-tauri/src/core_process_tests.rs @@ -1,11 +1,4 @@ -//! Sibling tests extracted from core_process.rs — see PR #835. - -use super::{ - current_rpc_token, default_core_bin, default_core_port, default_core_run_mode, - generate_rpc_token, same_executable_path, CoreProcessHandle, CoreRunMode, -}; -use std::io::Write; -use std::path::PathBuf; +use super::{current_rpc_token, default_core_port, generate_rpc_token, CoreProcessHandle}; use std::sync::{Mutex, MutexGuard, OnceLock}; fn env_lock() -> MutexGuard<'static, ()> { @@ -37,27 +30,13 @@ impl EnvGuard { impl Drop for EnvGuard { fn drop(&mut self) { - if let Some(old) = &self.old { - std::env::set_var(self.key, old); - } else { - std::env::remove_var(self.key); + match &self.old { + Some(v) => std::env::set_var(self.key, v), + None => std::env::remove_var(self.key), } } } -#[test] -fn default_core_run_mode_env_parsing() { - let _env_lock = env_lock(); - let _unset = EnvGuard::unset("OPENHUMAN_CORE_RUN_MODE"); - assert_eq!(default_core_run_mode(false), CoreRunMode::ChildProcess); - - let _guard = EnvGuard::set("OPENHUMAN_CORE_RUN_MODE", "in-process"); - assert_eq!(default_core_run_mode(false), CoreRunMode::InProcess); - - let _guard = EnvGuard::set("OPENHUMAN_CORE_RUN_MODE", "sidecar"); - assert_eq!(default_core_run_mode(false), CoreRunMode::ChildProcess); -} - #[test] fn default_core_port_env_and_fallback() { let _env_lock = env_lock(); @@ -68,161 +47,13 @@ fn default_core_port_env_and_fallback() { assert_eq!(default_core_port(), 8899); } -#[test] -fn same_executable_path_handles_equal_and_non_equal_paths() { - let current = std::env::current_exe().expect("current exe"); - assert!(same_executable_path(¤t, ¤t)); - - let different = current.with_file_name("definitely-not-the-current-exe"); - assert!(!same_executable_path(¤t, &different)); -} - -#[test] -fn same_executable_path_handles_symlinks() { - // Create a temp directory with a file and a symlink - let temp_dir = std::env::temp_dir().join("openhuman-test-"); - let _ = std::fs::remove_dir_all(&temp_dir); - std::fs::create_dir_all(&temp_dir).expect("create temp dir"); - - let real_file = temp_dir.join("real-binary"); - let mut file = std::fs::File::create(&real_file).expect("create file"); - file.write_all(b"test").expect("write test content"); - drop(file); - - // Test canonical comparison works - let symlink = temp_dir.join("symlink-binary"); - #[cfg(unix)] - std::os::unix::fs::symlink(&real_file, &symlink).expect("create symlink"); - #[cfg(windows)] - std::os::windows::fs::symlink_file(&real_file, &symlink).expect("create symlink"); - - // Symlink and real file should be considered the same - assert!( - same_executable_path(&real_file, &symlink), - "symlink should resolve to same path" - ); - - // Different files should not match - let other_file = temp_dir.join("other-binary"); - let mut file2 = std::fs::File::create(&other_file).expect("create other file"); - file2.write_all(b"other").expect("write other content"); - drop(file2); - - assert!( - !same_executable_path(&real_file, &other_file), - "different files should not match" - ); - - // Cleanup - let _ = std::fs::remove_dir_all(&temp_dir); -} - -// Tests for default_core_bin() - PR: make linux CEF deb package runnable -#[test] -fn default_core_bin_env_override_takes_precedence() { - let _env_lock = env_lock(); - let temp_dir = std::env::temp_dir().join("openhuman-core-test-"); - let _ = std::fs::remove_dir_all(&temp_dir); - std::fs::create_dir_all(&temp_dir).expect("create temp dir"); - - // Create a fake core binary - let fake_core = temp_dir.join("openhuman-core"); - let mut file = std::fs::File::create(&fake_core).expect("create fake core"); - file.write_all(b"fake binary").expect("write content"); - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - let perms = std::fs::Permissions::from_mode(0o755); - std::fs::set_permissions(&fake_core, perms).expect("set permissions"); - } - drop(file); - - // Set env override - let fake_core_str = fake_core.to_str().unwrap(); - let _guard = EnvGuard::set("OPENHUMAN_CORE_BIN", fake_core_str); - - let result = default_core_bin(); - assert!( - result.is_some(), - "env override should return Some when file exists" - ); - assert_eq!(result.unwrap(), fake_core, "should return the exact path"); - - // Cleanup - let _ = std::fs::remove_dir_all(&temp_dir); -} - -#[test] -fn default_core_bin_env_override_nonexistent_warns() { - let _env_lock = env_lock(); - let _guard = EnvGuard::set("OPENHUMAN_CORE_BIN", "/nonexistent/path/openhuman-core"); - - let _result = default_core_bin(); - // When env override is set but file doesn't exist, we log a warning and continue - // The function should continue to search other paths - // Result depends on whether a core binary exists elsewhere - // This test primarily verifies the function doesn't panic -} - -#[test] -fn default_core_bin_returns_none_when_no_binary_found() { - let _env_lock = env_lock(); - // Clear env override - let _guard = EnvGuard::unset("OPENHUMAN_CORE_BIN"); - - // Note: This test may pass or fail depending on whether there's actually - // a core binary in the expected locations. We verify the function - // returns a consistent type. - let _result = default_core_bin(); - // Function should not panic regardless of result -} - -#[test] -fn default_core_bin_prefers_staged_sidecar_in_dev() { - let _env_lock = env_lock(); - // This test verifies the dev build behavior where we look for - // staged binaries in src-tauri/binaries - // In test mode (debug_assertions), this path is checked - let _guard = EnvGuard::unset("OPENHUMAN_CORE_BIN"); - - // We can't easily test this without modifying the CARGO_MANIFEST_DIR - // but we can verify the function runs without panic - let _result = default_core_bin(); -} - -// Test for same_executable_path edge cases -#[test] -fn same_executable_path_handles_nonexistent_files() { - let nonexistent = PathBuf::from("/definitely/does/not/exist"); - let current = std::env::current_exe().expect("current exe"); - - // Should return false when one path doesn't exist - assert!( - !same_executable_path(&nonexistent, ¤t), - "nonexistent paths should not match existing" - ); - - // Both nonexistent should also return false (can't canonicalize) - let nonexistent2 = PathBuf::from("/also/does/not/exist"); - assert!( - !same_executable_path(&nonexistent, &nonexistent2), - "both nonexistent should return false" - ); -} - #[test] fn core_process_handle_new_creates_instance() { - let handle = CoreProcessHandle::new(9999, None, CoreRunMode::ChildProcess); + let handle = CoreProcessHandle::new(9999); assert_eq!(handle.port(), 9999); assert_eq!(handle.rpc_url(), "http://127.0.0.1:9999/rpc"); } -#[test] -fn core_process_handle_rpc_url_format() { - let handle = CoreProcessHandle::new(12345, None, CoreRunMode::ChildProcess); - assert_eq!(handle.rpc_url(), "http://127.0.0.1:12345/rpc"); -} - #[test] fn ensure_running_returns_ok_when_rpc_port_already_open() { let rt = tokio::runtime::Runtime::new().expect("runtime"); @@ -231,7 +62,7 @@ fn ensure_running_returns_ok_when_rpc_port_already_open() { .await .expect("bind test listener"); let port = listener.local_addr().expect("local addr").port(); - let handle = CoreProcessHandle::new(port, None, CoreRunMode::ChildProcess); + let handle = CoreProcessHandle::new(port); handle.ensure_running().await }); assert!( @@ -279,7 +110,7 @@ fn generate_rpc_token_is_not_constant() { /// bearer token immediately — no file I/O or timing dependency. #[test] fn core_process_handle_new_token_is_valid() { - let handle = CoreProcessHandle::new(19001, None, CoreRunMode::ChildProcess); + let handle = CoreProcessHandle::new(19001); let token = handle.rpc_token(); assert_eq!(token.len(), 64, "handle token must be 64 hex chars"); assert!( @@ -289,36 +120,32 @@ fn core_process_handle_new_token_is_valid() { } /// `CoreProcessHandle::new()` must NOT publish the token to the global -/// `CURRENT_RPC_TOKEN`. The global is set only after `ensure_running()` -/// successfully spawns the child that received `OPENHUMAN_CORE_TOKEN`. -/// Advertising the token before spawn would cause 401s when the port is -/// already held by a stale process that never received this token. +/// `CURRENT_RPC_TOKEN`. The global is set only after `ensure_running()` +/// successfully spawns the embedded server with `OPENHUMAN_CORE_TOKEN` in +/// scope. Advertising the token before spawn would 401 against any process +/// already listening on the port that never received this token. #[test] fn new_does_not_publish_global_token() { - // Capture current global state before constructing the handle. let before = current_rpc_token(); - let handle = CoreProcessHandle::new(19002, None, CoreRunMode::ChildProcess); + let handle = CoreProcessHandle::new(19002); let after = current_rpc_token(); - // The global must not have changed to this handle's token. assert_ne!( after.as_deref(), Some(handle.rpc_token()), "new() must not publish its token to CURRENT_RPC_TOKEN before ensure_running() spawns" ); - // Whatever was in the global before must still be there (or still None). assert_eq!( before, after, "new() must leave CURRENT_RPC_TOKEN unchanged" ); } -/// Two handles constructed sequentially must each have a unique token, -/// but neither should update the global until ensure_running() spawns. +/// Two handles constructed sequentially must each have a unique token. #[test] fn each_handle_has_unique_token() { - let h1 = CoreProcessHandle::new(19003, None, CoreRunMode::ChildProcess); - let h2 = CoreProcessHandle::new(19004, None, CoreRunMode::ChildProcess); + let h1 = CoreProcessHandle::new(19003); + let h2 = CoreProcessHandle::new(19004); assert_ne!( h1.rpc_token(), @@ -326,23 +153,3 @@ fn each_handle_has_unique_token() { "each handle must have a unique token" ); } - -// Tests for logging/diagnostics (grep-friendly patterns) -#[test] -fn core_bin_resolution_logs_expected_patterns() { - // These patterns are documented in the PR as grep-friendly diagnostics. - // We verify they exist in the source code by checking the function compiles. - // The actual log output is verified at runtime. - - // Expected log patterns from PR: - // "[core] default_core_bin: using OPENHUMAN_CORE_BIN override {path}" - // "[core] default_core_bin: OPENHUMAN_CORE_BIN override does not exist: {path}" - // "[core] default_core_bin: using packaged linux core binary {path}" - // "[core] default_core_bin: found standalone sibling binary {path}" - // "[core] default_core_bin: found legacy standalone binary {path}" - // "[core] default_core_bin: found bundled sidecar {path}" - // "[core] default_core_bin: no dedicated core binary found" - - // This test ensures the function is callable and returns expected types - let _ = default_core_bin(); -} diff --git a/app/src-tauri/src/core_update.rs b/app/src-tauri/src/core_update.rs deleted file mode 100644 index 3f5ba0ad9..000000000 --- a/app/src-tauri/src/core_update.rs +++ /dev/null @@ -1,776 +0,0 @@ -//! Core sidecar version checking and auto-update logic. -//! -//! After the Tauri shell starts the core sidecar, it queries `core.version` via -//! JSON-RPC. If the running core is older than the minimum expected version, the -//! shell downloads the latest release from GitHub, stages it, kills the old -//! process, and restarts with the new binary. - -use std::io::Write; -use std::path::{Path, PathBuf}; - -use serde::{Deserialize, Serialize}; - -use crate::core_process::CoreProcessHandle; - -/// The minimum core version this Tauri build expects. -/// Bump this when the app depends on new core RPC methods. -pub const MINIMUM_CORE_VERSION: &str = env!("CARGO_PKG_VERSION"); - -/// GitHub owner/repo for releases. -const GITHUB_OWNER: &str = "tinyhumansai"; -const GITHUB_REPO: &str = "openhuman"; - -#[derive(Debug, Deserialize)] -struct RpcResponse { - result: Option, - error: Option, -} - -#[derive(Debug, Deserialize)] -struct GitHubRelease { - tag_name: String, - assets: Vec, -} - -#[derive(Debug, Deserialize)] -struct GitHubAsset { - name: String, - browser_download_url: String, -} - -/// Returned by `check_core_update` Tauri command. -#[derive(Debug, Clone, Serialize)] -pub struct CoreUpdateInfo { - pub running_version: String, - pub minimum_version: String, - /// True if running < minimum (compatibility issue). - pub outdated: bool, - /// Latest version on GitHub Releases (if fetch succeeded). - pub latest_version: Option, - /// True if running < latest (newer release available). - pub update_available: bool, -} - -/// Query the running core's version via JSON-RPC. -pub async fn query_core_version(rpc_url: &str, rpc_token: &str) -> Result { - let client = reqwest::Client::builder() - .timeout(std::time::Duration::from_secs(5)) - .build() - .map_err(|e| format!("http client error: {e}"))?; - - let body = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "method": "core.version", - "params": {} - }); - - let resp = client - .post(rpc_url) - // `apply_auth()` reads from the process-global CURRENT_RPC_TOKEN, but - // this function accepts an explicit token so it can run immediately - // after the core process spawns — before publish_rpc_token() is called. - // If the Authorization header format ever changes, update both this - // site and `core_rpc::apply_auth()` together. - .header("Authorization", format!("Bearer {rpc_token}")) - .json(&body) - .send() - .await - .map_err(|e| format!("failed to query core.version: {e}"))?; - - let rpc: RpcResponse = resp - .json() - .await - .map_err(|e| format!("failed to parse core.version response: {e}"))?; - - if let Some(err) = rpc.error { - return Err(format!("core.version RPC error: {err}")); - } - - let version = rpc - .result - .and_then(|v| v.get("version").and_then(|v| v.as_str()).map(String::from)) - .ok_or_else(|| "core.version response missing 'version' field".to_string())?; - - Ok(version) -} - -/// Compare two version strings. Returns true if `running` is older than `target`. -pub fn is_outdated(running: &str, target: &str) -> bool { - let parse = |v: &str| -> Option { - semver::Version::parse(v.trim_start_matches('v')).ok() - }; - match (parse(running), parse(target)) { - (Some(r), Some(t)) => r < t, - _ => { - log::warn!("[core-update] could not parse versions running={running} target={target}"); - false - } - } -} - -/// Full check: query running version, compare against minimum AND latest GitHub release. -pub async fn check_full(rpc_url: &str, rpc_token: &str) -> Result { - let running = query_core_version(rpc_url, rpc_token).await?; - let minimum = MINIMUM_CORE_VERSION; - let outdated = is_outdated(&running, minimum); - - // Best-effort fetch of latest release — don't fail the whole check if GitHub is unreachable. - let (latest_version, update_available) = match fetch_latest_release().await { - Ok(release) => { - let latest = release.tag_name.trim_start_matches('v').to_string(); - let available = is_outdated(&running, &latest); - (Some(latest), available) - } - Err(e) => { - log::warn!("[core-update] could not fetch latest release: {e}"); - (None, false) - } - }; - - Ok(CoreUpdateInfo { - running_version: running, - minimum_version: minimum.to_string(), - outdated, - latest_version, - update_available, - }) -} - -/// Build the platform triple for asset matching. -fn platform_triple() -> &'static str { - #[cfg(all(target_arch = "x86_64", target_os = "macos"))] - { - "x86_64-apple-darwin" - } - #[cfg(all(target_arch = "aarch64", target_os = "macos"))] - { - "aarch64-apple-darwin" - } - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - { - "x86_64-unknown-linux-gnu" - } - #[cfg(all(target_arch = "aarch64", target_os = "linux"))] - { - "aarch64-unknown-linux-gnu" - } - #[cfg(all(target_arch = "x86_64", target_os = "windows"))] - { - "x86_64-pc-windows-msvc" - } - #[cfg(all(target_arch = "aarch64", target_os = "windows"))] - { - "aarch64-pc-windows-msvc" - } -} - -/// Find the right asset for this platform. -/// -/// Current release format (since 0.52.x): `openhuman-core--.tar.gz` -/// on Unix, `.zip` on Windows. The archive contains a single `openhuman-core` -/// (or `openhuman-core.exe`) file with no wrapping directory. -/// -/// Legacy format (kept as fallback for older releases): a raw binary named -/// `openhuman-core-` (or `.exe`). -fn find_platform_asset(assets: &[GitHubAsset]) -> Option<&GitHubAsset> { - let triple = platform_triple(); - let archive_ext = if cfg!(windows) { ".zip" } else { ".tar.gz" }; - - // New versioned-archive format: `openhuman-core-0.52.26-aarch64-apple-darwin.tar.gz` - let archive_match = assets.iter().find(|a| { - a.name.starts_with("openhuman-core-") - && a.name.contains(triple) - && a.name.ends_with(archive_ext) - // Defensive: avoid matching detached signatures or checksums that - // happen to share the prefix (e.g. `…tar.gz.sha256`, `…tar.gz.sig`). - && !a.name.ends_with(".sha256") - && !a.name.ends_with(".sig") - }); - if archive_match.is_some() { - return archive_match; - } - - // Legacy raw-binary format. - let legacy = format!("openhuman-core-{triple}"); - let legacy_exe = format!("{legacy}.exe"); - assets - .iter() - .find(|a| a.name == legacy || a.name == legacy_exe) -} - -/// Filename the staged core binary must be saved as for `core_process::default_core_bin` -/// to discover it on subsequent runs. -fn staged_binary_name() -> String { - let triple = platform_triple(); - if cfg!(windows) { - format!("openhuman-core-{triple}.exe") - } else { - format!("openhuman-core-{triple}") - } -} - -/// True if the asset name looks like an archive we need to extract (vs. a raw binary). -fn is_archive_asset(name: &str) -> bool { - name.ends_with(".tar.gz") || name.ends_with(".tgz") || name.ends_with(".zip") -} - -/// Fetch the latest release from GitHub. -async fn fetch_latest_release() -> Result { - let url = format!("https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/releases/latest"); - - let client = reqwest::Client::builder() - .user_agent("openhuman-tauri-updater") - .timeout(std::time::Duration::from_secs(15)) - .build() - .map_err(|e| format!("http client error: {e}"))?; - - let resp = client - .get(&url) - .header("Accept", "application/vnd.github+json") - .send() - .await - .map_err(|e| format!("failed to fetch latest release: {e}"))?; - - if !resp.status().is_success() { - return Err(format!("GitHub API error: {}", resp.status())); - } - - resp.json() - .await - .map_err(|e| format!("failed to parse release: {e}")) -} - -/// Build a unique sibling temp path next to `dest` to stage writes before an atomic rename. -fn unique_tmp_path(dest: &Path) -> PathBuf { - let tmp_name = format!( - ".openhuman-update-{}.tmp", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .map(|d| d.as_millis()) - .unwrap_or(0) - ); - dest.parent() - .unwrap_or_else(|| std::path::Path::new(".")) - .join(tmp_name) -} - -/// Make a file executable (Unix) and rename it atomically to `dest`. On rename -/// failure the temp file is best-effort cleaned up. -fn finalize_executable(tmp: &Path, dest: &Path) -> Result<(), String> { - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(tmp, std::fs::Permissions::from_mode(0o755)) - .map_err(|e| format!("set permissions: {e}"))?; - } - std::fs::rename(tmp, dest).map_err(|e| { - let _ = std::fs::remove_file(tmp); - format!("rename staged binary: {e}") - }) -} - -/// Extract the inner core binary from a downloaded archive into `dest`. -/// -/// The archive is expected to contain a single file named `openhuman-core` -/// (or `openhuman-core.exe`) at the root — matching the layout produced by -/// the release workflow. `dest` must be the final binary path (with the -/// platform-triple-suffixed name `default_core_bin` looks for). -fn extract_archive(archive_path: &Path, dest: &Path) -> Result<(), String> { - let inner_name = if cfg!(windows) { - "openhuman-core.exe" - } else { - "openhuman-core" - }; - - let archive_name = archive_path - .file_name() - .and_then(|s| s.to_str()) - .unwrap_or(""); - - let file = std::fs::File::open(archive_path).map_err(|e| format!("open archive: {e}"))?; - - if archive_name.ends_with(".zip") { - let mut zip = zip::ZipArchive::new(file).map_err(|e| format!("read zip: {e}"))?; - let mut entry = zip - .by_name(inner_name) - .map_err(|e| format!("zip entry '{inner_name}' missing: {e}"))?; - let tmp = unique_tmp_path(dest); - { - let mut out = std::fs::File::create(&tmp).map_err(|e| format!("create temp: {e}"))?; - std::io::copy(&mut entry, &mut out).map_err(|e| format!("extract zip: {e}"))?; - out.flush().map_err(|e| format!("flush extracted: {e}"))?; - } - finalize_executable(&tmp, dest)?; - return Ok(()); - } - - // Default: tar.gz / tgz - let gz = flate2::read::GzDecoder::new(file); - let mut tar = tar::Archive::new(gz); - let entries = tar - .entries() - .map_err(|e| format!("read tar entries: {e}"))?; - for entry in entries { - let mut entry = entry.map_err(|e| format!("tar entry: {e}"))?; - let entry_path = entry.path().map_err(|e| format!("entry path: {e}"))?; - let matches = entry_path - .file_name() - .and_then(|s| s.to_str()) - .map(|n| n == inner_name) - .unwrap_or(false); - if !matches { - continue; - } - let tmp = unique_tmp_path(dest); - { - let mut out = std::fs::File::create(&tmp).map_err(|e| format!("create temp: {e}"))?; - std::io::copy(&mut entry, &mut out).map_err(|e| format!("extract tar: {e}"))?; - out.flush().map_err(|e| format!("flush extracted: {e}"))?; - } - finalize_executable(&tmp, dest)?; - return Ok(()); - } - - Err(format!( - "archive {} contained no entry named '{inner_name}'", - archive_path.display() - )) -} - -/// Download `url` to `dest` atomically. Used for both raw binaries (legacy -/// release format) and archive files (current format — caller then extracts). -async fn download_to_file(url: &str, dest: &Path) -> Result<(), String> { - let client = reqwest::Client::builder() - .user_agent("openhuman-tauri-updater") - .timeout(std::time::Duration::from_secs(300)) - .build() - .map_err(|e| format!("http client error: {e}"))?; - - let resp = client - .get(url) - .send() - .await - .map_err(|e| format!("download failed: {e}"))?; - - if !resp.status().is_success() { - return Err(format!("download returned status {}", resp.status())); - } - - let bytes = resp - .bytes() - .await - .map_err(|e| format!("failed to read download: {e}"))?; - - log::info!( - "[core-update] downloaded {} bytes to {}", - bytes.len(), - dest.display() - ); - - let tmp = unique_tmp_path(dest); - { - let mut file = std::fs::File::create(&tmp).map_err(|e| format!("create temp file: {e}"))?; - file.write_all(&bytes) - .map_err(|e| format!("write temp file: {e}"))?; - file.flush().map_err(|e| format!("flush temp file: {e}"))?; - } - - // Move into place. Caller is responsible for marking executable when the - // payload is a raw binary; archives stay non-executable on disk. - std::fs::rename(&tmp, dest).map_err(|e| { - let _ = std::fs::remove_file(&tmp); - format!("rename downloaded file: {e}") - })?; - - Ok(()) -} - -/// The main auto-update flow, called after the core process starts. -/// -/// When `force` is false (startup auto-check), only updates if the running core -/// is older than `MINIMUM_CORE_VERSION`. When `force` is true (manual trigger), -/// updates whenever GitHub has a newer version than what's currently running. -/// -/// Emits Tauri events so the frontend can show progress. -pub async fn check_and_update_core( - handle: CoreProcessHandle, - app: Option>, - force: bool, -) -> Result<(), String> { - let rpc_url = handle.rpc_url(); - let rpc_token = handle.rpc_token().to_string(); - log::info!( - "[core-update] checking core version at {} (minimum: {}, force: {})", - rpc_url, - MINIMUM_CORE_VERSION, - force - ); - - // Step 1: Query running version. - let running_version = match query_core_version(&rpc_url, &rpc_token).await { - Ok(v) => v, - Err(e) => { - log::warn!("[core-update] could not query core version: {e}"); - return Err(e); - } - }; - - log::info!( - "[core-update] running core version: {} (minimum: {})", - running_version, - MINIMUM_CORE_VERSION - ); - - let below_app_minimum = is_outdated(&running_version, MINIMUM_CORE_VERSION); - if below_app_minimum { - log::warn!( - "[core-update] sidecar is OLDER than this app build (running {running_version}, need >= {min}). \ -UI features (e.g. channel connect) may not match RPC until the core is updated.", - min = MINIMUM_CORE_VERSION - ); - } - - // Step 2: Fetch latest release from GitHub (needed to download a replacement binary). - emit_event(&app, "core-update:status", "checking"); - - let release = match fetch_latest_release().await { - Ok(r) => r, - Err(e) => { - if force { - log::warn!("[core-update] could not fetch latest release: {e}"); - return Err(e); - } - if below_app_minimum { - log::error!( - "[core-update] cannot auto-update core (GitHub unreachable): {e}\n\ -→ Stop any other `openhuman` / OpenHuman using RPC port {}.\n\ -→ From repo root: `cargo build --manifest-path Cargo.toml --bin openhuman` then `cd app && yarn core:stage`, restart the app.\n\ -→ Or fix network access to https://api.github.com (VPN/DNS/firewall).", - handle.port() - ); - emit_event(&app, "core-update:status", "error"); - return Err(e); - } - log::warn!( - "[core-update] could not fetch latest release (non-fatal; core meets minimum): {e}" - ); - emit_event(&app, "core-update:status", "up_to_date"); - return Ok(()); - } - }; - - let latest_version = release.tag_name.trim_start_matches('v').to_string(); - log::info!("[core-update] latest release: {latest_version}"); - - // Decide whether to proceed with the update. - let needs_update = if force { - // Manual trigger: update if GitHub has anything newer than what's running. - is_outdated(&running_version, &latest_version) - } else { - // Auto-check: only update if running is below the minimum the app requires. - is_outdated(&running_version, MINIMUM_CORE_VERSION) - }; - - if !needs_update { - log::info!("[core-update] no update needed (running: {running_version}, latest: {latest_version}, force: {force})"); - emit_event(&app, "core-update:status", "up_to_date"); - return Ok(()); - } - - log::warn!( - "[core-update] updating core {} → {} (force: {})", - running_version, - latest_version, - force - ); - - let asset = find_platform_asset(&release.assets).ok_or_else(|| { - format!( - "no matching asset for platform '{}' in release {}", - platform_triple(), - latest_version - ) - })?; - - log::info!( - "[core-update] found asset: {} ({})", - asset.name, - asset.browser_download_url - ); - - emit_event(&app, "core-update:status", "downloading"); - - // Step 3: Determine staging directory. - let staging_dir = resolve_staging_dir(); - if let Some(ref dir) = staging_dir { - if !dir.exists() { - std::fs::create_dir_all(dir).map_err(|e| format!("create staging dir: {e}"))?; - } - } - - // Where the downloaded asset lands (named after the release asset). - let download_dest = staging_dir - .as_ref() - .map(|d| d.join(&asset.name)) - .unwrap_or_else(|| PathBuf::from(&asset.name)); - // Final binary path that `default_core_bin` will pick up next launch. - let binary_dest = staging_dir - .as_ref() - .map(|d| d.join(staged_binary_name())) - .unwrap_or_else(|| PathBuf::from(staged_binary_name())); - let asset_is_archive = is_archive_asset(&asset.name); - - // Step 4: Acquire restart lock, shutdown old process, download, stage, restart. - // Hold the lock across download + staging + restart to prevent concurrent updates. - { - let _guard = handle.restart_lock().await; - log::debug!("[core-update] acquired restart lock"); - - // Shutdown old process first so the binary isn't in use during staging. - handle.shutdown().await; - - // Wait for port to free. - let mut waited = 0u64; - while waited < 10_000 { - if !port_open(handle.port()).await { - break; - } - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - waited += 50; - } - - // Download the asset. - download_to_file(&asset.browser_download_url, &download_dest).await?; - log::info!( - "[core-update] downloaded asset to {}", - download_dest.display() - ); - - if asset_is_archive { - // Extract the inner `openhuman-core` binary into the staged location. - extract_archive(&download_dest, &binary_dest)?; - log::info!( - "[core-update] extracted core binary to {}", - binary_dest.display() - ); - // Best-effort cleanup of the archive (don't fail the update if this fails). - if let Err(e) = std::fs::remove_file(&download_dest) { - log::warn!( - "[core-update] could not remove archive {}: {e}", - download_dest.display() - ); - } - } else { - // Legacy raw-binary asset: rename into the canonical staged path - // and mark executable. - if download_dest != binary_dest { - std::fs::rename(&download_dest, &binary_dest) - .map_err(|e| format!("rename legacy binary: {e}"))?; - } - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(&binary_dest, std::fs::Permissions::from_mode(0o755)) - .map_err(|e| format!("set permissions on staged binary: {e}"))?; - } - log::info!( - "[core-update] staged legacy raw binary at {}", - binary_dest.display() - ); - } - - // Point the handle at the new binary so ensure_running launches it. - handle.set_core_bin(binary_dest).await; - - emit_event(&app, "core-update:status", "restarting"); - - // Restart with the new binary. - handle.ensure_running().await?; - } - - log::info!( - "[core-update] core updated from {} to {} and restarted", - running_version, - latest_version - ); - - emit_event(&app, "core-update:status", "updated"); - - Ok(()) -} - -/// Resolve the directory where staged sidecar binaries are placed. -/// Mirrors the discovery logic in `core_process::default_core_bin()`. -fn resolve_staging_dir() -> Option { - // Dev: src-tauri/binaries/ - #[cfg(debug_assertions)] - { - let binaries_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("binaries"); - if binaries_dir.exists() { - return Some(binaries_dir); - } - } - - // Production: next to the executable, or Resources/ on macOS. - let exe = std::env::current_exe().ok()?; - let exe_dir = exe.parent()?; - - #[cfg(target_os = "macos")] - { - if let Some(resources) = exe_dir.parent().map(|p| p.join("Resources")) { - if resources.exists() { - return Some(resources); - } - } - } - - Some(exe_dir.to_path_buf()) -} - -async fn port_open(port: u16) -> bool { - matches!( - tokio::time::timeout( - std::time::Duration::from_millis(150), - tokio::net::TcpStream::connect(("127.0.0.1", port)), - ) - .await, - Ok(Ok(_)) - ) -} - -fn emit_event(app: &Option>, event: &str, payload: &str) { - if let Some(app) = app { - use tauri::Emitter; - if let Err(e) = app.emit(event, payload) { - log::warn!("[core-update] failed to emit {event}: {e}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn asset(name: &str) -> GitHubAsset { - GitHubAsset { - name: name.to_string(), - browser_download_url: format!("https://example.test/{name}"), - } - } - - #[test] - fn find_platform_asset_matches_versioned_archive() { - let triple = platform_triple(); - let archive_ext = if cfg!(windows) { "zip" } else { "tar.gz" }; - let archive_name = format!("openhuman-core-0.52.26-{triple}.{archive_ext}"); - let assets = vec![ - asset("latest.json"), - asset(&format!("{archive_name}.sha256")), - asset(&archive_name), - asset(&format!("{archive_name}.sig")), - asset(&format!("OpenHuman_0.52.26_{triple}.app.tar.gz")), - ]; - let m = find_platform_asset(&assets).expect("should match versioned archive"); - assert_eq!(m.name, archive_name); - } - - #[test] - fn find_platform_asset_falls_back_to_legacy_raw_binary() { - let triple = platform_triple(); - let legacy_name = if cfg!(windows) { - format!("openhuman-core-{triple}.exe") - } else { - format!("openhuman-core-{triple}") - }; - let assets = vec![asset("latest.json"), asset(&legacy_name)]; - let m = find_platform_asset(&assets).expect("legacy raw binary should match"); - assert_eq!(m.name, legacy_name); - } - - #[test] - fn find_platform_asset_skips_signatures_and_checksums() { - let triple = platform_triple(); - let archive_ext = if cfg!(windows) { "zip" } else { "tar.gz" }; - let assets = vec![ - asset(&format!( - "openhuman-core-0.52.26-{triple}.{archive_ext}.sha256" - )), - asset(&format!( - "openhuman-core-0.52.26-{triple}.{archive_ext}.sig" - )), - ]; - assert!(find_platform_asset(&assets).is_none()); - } - - #[test] - fn is_archive_asset_recognises_known_extensions() { - assert!(is_archive_asset( - "openhuman-core-0.52.26-aarch64-apple-darwin.tar.gz" - )); - assert!(is_archive_asset( - "openhuman-core-0.52.26-x86_64-pc-windows-msvc.zip" - )); - assert!(is_archive_asset("foo.tgz")); - assert!(!is_archive_asset("openhuman-core-aarch64-apple-darwin")); - assert!(!is_archive_asset("openhuman-core.exe")); - } - - #[test] - fn extract_archive_pulls_inner_binary_from_targz() { - use std::io::Read; - - let dir = std::env::temp_dir().join(format!( - "oh-extract-test-{}", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos() - )); - std::fs::create_dir_all(&dir).unwrap(); - - // Build an in-memory tar.gz with a single `openhuman-core` (or .exe) entry. - let inner = if cfg!(windows) { - "openhuman-core.exe" - } else { - "openhuman-core" - }; - let payload = b"#!fake-binary-bytes"; - - let archive_path = dir.join("test.tar.gz"); - { - let tar_gz = std::fs::File::create(&archive_path).unwrap(); - let enc = flate2::write::GzEncoder::new(tar_gz, flate2::Compression::default()); - let mut builder = tar::Builder::new(enc); - let mut header = tar::Header::new_gnu(); - header.set_size(payload.len() as u64); - header.set_mode(0o755); - header.set_cksum(); - builder - .append_data(&mut header, inner, &payload[..]) - .unwrap(); - builder.into_inner().unwrap().finish().unwrap(); - } - - let dest = dir.join("openhuman-core-staged"); - extract_archive(&archive_path, &dest).expect("extract should succeed"); - - let mut got = Vec::new(); - std::fs::File::open(&dest) - .unwrap() - .read_to_end(&mut got) - .unwrap(); - assert_eq!(got, payload); - - let _ = std::fs::remove_dir_all(&dir); - } - - #[test] - fn outdated_detection() { - assert!(is_outdated("0.49.17", "0.51.8")); - assert!(is_outdated("0.50.0", "0.51.0")); - assert!(!is_outdated("0.51.8", "0.51.8")); - assert!(!is_outdated("0.52.0", "0.51.8")); - assert!(!is_outdated("1.0.0", "0.51.8")); - } -} diff --git a/app/src-tauri/src/lib.rs b/app/src-tauri/src/lib.rs index c3d41c284..58e906101 100644 --- a/app/src-tauri/src/lib.rs +++ b/app/src-tauri/src/lib.rs @@ -7,7 +7,6 @@ mod cef_preflight; mod cef_profile; mod core_process; mod core_rpc; -mod core_update; mod discord_scanner; mod gmail; mod gmessages_scanner; @@ -211,113 +210,31 @@ fn configure_overlay_window_macos(window: &WebviewWindow) { } } -/// Resolve the core binary, preferring the staged sidecar. -fn resolve_core_bin() -> Result { - if let Some(bin) = core_process::default_core_bin() { - return Ok(bin); - } - std::env::current_exe().map_err(|e| format!("cannot resolve executable: {e}")) -} - -/// Run the core binary with the given CLI args and return its stdout. -async fn run_core_cli(args: Vec) -> Result { - tokio::task::spawn_blocking(move || { - let bin = resolve_core_bin()?; - let is_self = { - let current = std::env::current_exe().ok(); - current - .as_ref() - .and_then(|c| std::fs::canonicalize(c).ok()) - .zip(std::fs::canonicalize(&bin).ok()) - .map_or(false, |(a, b)| a == b) - }; - - let mut cmd = std::process::Command::new(&bin); - if is_self { - cmd.arg("core"); - } - cmd.args(&args); - - #[cfg(windows)] - { - use std::os::windows::process::CommandExt; - const CREATE_NO_WINDOW: u32 = 0x0800_0000; - cmd.creation_flags(CREATE_NO_WINDOW); - } - - log::info!( - "[service-direct] running {:?} {}{}", - bin, - if is_self { "core " } else { "" }, - args.join(" ") - ); - - let output = cmd - .output() - .map_err(|e| format!("failed to execute core binary: {e}"))?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - return Err(format!( - "core binary exited with {}: {}", - output.status, - stderr.trim() - )); - } - - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - }) - .await - .map_err(|e| format!("task join error: {e}"))? -} - -#[tauri::command] -async fn service_install_direct() -> Result { - run_core_cli(vec!["service".into(), "install".into()]).await -} - -#[tauri::command] -async fn service_start_direct() -> Result { - run_core_cli(vec!["service".into(), "start".into()]).await -} - -#[tauri::command] -async fn service_stop_direct() -> Result { - run_core_cli(vec!["service".into(), "stop".into()]).await -} - -#[tauri::command] -async fn service_status_direct() -> Result { - run_core_cli(vec!["service".into(), "status".into()]).await -} - -#[tauri::command] -async fn service_uninstall_direct() -> Result { - run_core_cli(vec!["service".into(), "uninstall".into()]).await -} - -/// Check if the core sidecar is outdated and whether a newer version is available on GitHub. -/// Returns version info, compatibility status, and update availability. +/// Core update is handled by the Tauri shell auto-updater (`tauri-plugin-updater`) +/// since the core ships in-process with the app. This command is kept as a +/// no-op stub so the frontend's `checkCoreUpdate` keeps working without errors; +/// it always reports the running version as up-to-date. #[tauri::command] async fn check_core_update( - state: tauri::State<'_, core_process::CoreProcessHandle>, + _state: tauri::State<'_, core_process::CoreProcessHandle>, ) -> Result { - let rpc_url = state.inner().rpc_url(); - let rpc_token = state.inner().rpc_token().to_string(); - let info = core_update::check_full(&rpc_url, &rpc_token).await?; - serde_json::to_value(&info).map_err(|e| format!("serialize error: {e}")) + let version = env!("CARGO_PKG_VERSION"); + Ok(serde_json::json!({ + "running_version": version, + "minimum_version": version, + "outdated": false, + "latest_version": version, + "update_available": false, + })) } -/// Trigger a full core update: download latest from GitHub, stage, kill old, restart. -/// Uses `force=true` so it updates to the latest release even if the running core -/// meets the minimum version requirement. +/// Stub kept for frontend compatibility — use `apply_app_update` instead. #[tauri::command] async fn apply_core_update( - state: tauri::State<'_, core_process::CoreProcessHandle>, - app: tauri::AppHandle, + _state: tauri::State<'_, core_process::CoreProcessHandle>, + _app: tauri::AppHandle, ) -> Result<(), String> { - log::info!("[core-update] manual apply_core_update invoked from frontend"); - core_update::check_and_update_core(state.inner().clone(), Some(app), true).await + Err("core ships in-process; use the Tauri shell updater (apply_app_update) instead".into()) } #[tauri::command] @@ -1098,17 +1015,9 @@ pub fn run() { return Err("webview_apis bridge failed to start — aborting setup".into()); } - let core_run_mode = core_process::default_core_run_mode(daemon_mode); - let core_bin = if matches!(core_run_mode, core_process::CoreRunMode::ChildProcess) { - core_process::default_core_bin() - } else { - None - }; - let core_handle = core_process::CoreProcessHandle::new( - core_process::default_core_port(), - core_bin, - core_run_mode, - ); + let _ = daemon_mode; + let core_handle = + core_process::CoreProcessHandle::new(core_process::default_core_port()); std::env::set_var("OPENHUMAN_CORE_RPC_URL", core_handle.rpc_url()); // Expose the shared CEF cookies SQLite path to the core sidecar @@ -1131,25 +1040,12 @@ pub fn run() { } app.manage(core_handle.clone()); - let app_handle_for_update = app.handle().clone(); tauri::async_runtime::spawn(async move { if let Err(err) = core_handle.ensure_running().await { - log::error!("[core] failed to start core process: {err}"); + log::error!("[core] failed to start embedded core: {err}"); return; } - log::info!("[core] core process ready"); - - // Check if the running core is outdated and auto-update if needed. - let update_handle = core_handle.clone(); - if let Err(err) = core_update::check_and_update_core( - update_handle, - Some(app_handle_for_update), - false, - ) - .await - { - log::warn!("[core-update] auto-update check failed (non-fatal): {err}"); - } + log::info!("[core] embedded core ready"); }); // Restore last-known window position+size before showing the @@ -1510,11 +1406,6 @@ pub fn run() { restart_app, get_active_user_id, schedule_cef_profile_purge, - service_install_direct, - service_start_direct, - service_stop_direct, - service_status_direct, - service_uninstall_direct, register_dictation_hotkey, unregister_dictation_hotkey, webview_accounts::webview_account_open, @@ -1613,31 +1504,81 @@ pub fn run() { if let Some(core) = app_handle.try_state::() { let core = core.inner().clone(); + // Aborts the embedded server task. Synchronous and safe on + // the UI thread — `JoinHandle::abort` returns immediately. tauri::async_runtime::block_on(async move { core.send_terminate_signal().await; }); } + // Give CEF's UI message loop a brief window to process the + // queued browser close messages before the runtime calls + // `cef::shutdown()`. Without this, a webview that was mid-load + // when the user quit can race the shutdown and leave its + // renderer helper orphaned (re-parented to launchd on macOS). + std::thread::sleep(std::time::Duration::from_millis(50)); + log::info!("[app] RunEvent::ExitRequested — early teardown complete"); } RunEvent::Exit => { - log::info!("[app] RunEvent::Exit"); + log::info!("[app] RunEvent::Exit — cef::shutdown follows"); } _ => {} }); + + // Belt-and-suspenders sweep: after Tauri's event loop returns the + // vendored runtime has already called `cef::shutdown()`. In normal + // operation every CEF helper (GPU / Network / Utility / Renderer) is + // gone by now. If anything is still alive — e.g. a renderer that was + // mid-spawn when the user quit — it would otherwise be re-parented to + // launchd on macOS / init on Linux and survive the GUI exit. SIGTERM + // its children before this process actually exits. + // + // We don't `wait()` on them: the kernel will reap them as our exit + // unwinds, and any helper that ignores SIGTERM is a CEF bug we'd + // rather see in Activity Monitor than silently SIGKILL. + sweep_orphan_children(); +} + +/// Send SIGTERM to every direct child of the current process. No-op on +/// non-Unix platforms (Windows job objects already kill CEF helpers when +/// the parent exits). +fn sweep_orphan_children() { + #[cfg(unix)] + { + let pid = std::process::id(); + match std::process::Command::new("pkill") + .args(["-TERM", "-P", &pid.to_string()]) + .status() + { + Ok(status) => { + // pkill exits 0 if it killed at least one process, 1 if no + // matches (the healthy case after cef::shutdown), 2/3 on + // error. Both 0 and 1 are expected; log 0 loudly so we + // notice when the safety net actually catches something. + match status.code() { + Some(0) => log::warn!( + "[app] sweep: SIGTERM'd leftover child processes after cef::shutdown" + ), + Some(1) => log::info!("[app] sweep: no leftover children (clean exit)"), + other => log::warn!("[app] sweep: pkill exited with {:?}", other), + } + } + Err(e) => log::warn!("[app] sweep: failed to invoke pkill: {e}"), + } + } + #[cfg(not(unix))] + { + log::debug!("[app] sweep: skipped on non-unix platform"); + } } pub fn run_core_from_args(args: &[String]) -> Result<(), String> { - let core_bin = crate::core_process::default_core_bin() - .ok_or_else(|| "openhuman-core binary not found".to_string())?; - let status = std::process::Command::new(core_bin) - .args(args) - .status() - .map_err(|e| format!("failed to execute core binary: {e}"))?; - if !status.success() { - return Err(format!("core binary exited with status {status}")); - } - Ok(()) + // Core lives in-process: dispatch directly through the linked `openhuman_core` + // library instead of shelling out to a separate binary. The Tauri main() + // routes `OpenHuman core ` here so users can still drive the core CLI + // from the bundled app. + openhuman_core::run_core_from_args(args).map_err(|e| format!("{e:#}")) } // --------------------------------------------------------------------------- diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json index 475804b8d..3e83cf63c 100644 --- a/app/src-tauri/tauri.conf.json +++ b/app/src-tauri/tauri.conf.json @@ -4,9 +4,9 @@ "version": "0.53.4", "identifier": "com.openhuman.app", "build": { - "beforeDevCommand": "pnpm run core:stage && pnpm run dev", + "beforeDevCommand": "pnpm run dev", "devUrl": "http://localhost:1420", - "beforeBuildCommand": "pnpm run build:app && pnpm run core:stage", + "beforeBuildCommand": "pnpm run build:app", "frontendDist": "../dist" }, "app": { @@ -48,9 +48,6 @@ "../../src/openhuman/agent/prompts", "recipes/**/*" ], - "externalBin": [ - "binaries/openhuman-core" - ], "linux": { "deb": { "depends": [ diff --git a/package.json b/package.json index 41f791c86..a27c41f8b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "scripts": { "build": "pnpm --filter openhuman-app build", "compile": "pnpm --filter openhuman-app compile", - "core:stage": "pnpm --filter openhuman-app core:stage", "dev": "pnpm --filter openhuman-app dev", "dev:app": "pnpm --filter openhuman-app dev:app", "dev:cef": "pnpm --filter openhuman-app dev:cef", diff --git a/scripts/release/stage-sidecar.sh b/scripts/release/stage-sidecar.sh deleted file mode 100755 index 5a4236162..000000000 --- a/scripts/release/stage-sidecar.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -# Stage the core sidecar binary next to Tauri resources for bundling. -# -# Usage: -# stage-sidecar.sh -# -# Example: -# stage-sidecar.sh aarch64-apple-darwin target/aarch64-apple-darwin/release openhuman-core openhuman-core -set -euo pipefail - -TARGET="${1:?Usage: stage-sidecar.sh }" -CORE_TARGET_DIR="${2:?}" -CORE_BIN_NAME="${3:?}" -SIDECAR_BASE="${4:?}" - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" - -EXE_SUFFIX="" -if [[ "$TARGET" == *"windows"* ]]; then - EXE_SUFFIX=".exe" -fi - -SOURCE="${REPO_ROOT}/${CORE_TARGET_DIR}/${CORE_BIN_NAME}${EXE_SUFFIX}" -DEST_DIR="${REPO_ROOT}/app/src-tauri/binaries" -DEST="${DEST_DIR}/${SIDECAR_BASE}-${TARGET}${EXE_SUFFIX}" - -mkdir -p "$DEST_DIR" -cp "$SOURCE" "$DEST" - -if [[ "$TARGET" != *"windows"* ]]; then - chmod +x "$DEST" -fi - -echo "[stage-sidecar] Staged: $DEST" - -# ── Verify ─────────────────────────────────────────────────────────────────── -if [ ! -f "$DEST" ]; then - echo "[stage-sidecar] ERROR: Missing staged sidecar binary: $DEST" - exit 1 -fi - -if [[ "$TARGET" != *"windows"* ]] && [ ! -x "$DEST" ]; then - echo "[stage-sidecar] ERROR: Staged sidecar is not executable: $DEST" - exit 1 -fi - -echo "[stage-sidecar] Verified OK" diff --git a/scripts/stage-core-sidecar.mjs b/scripts/stage-core-sidecar.mjs deleted file mode 100644 index fe7188736..000000000 --- a/scripts/stage-core-sidecar.mjs +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from "node:child_process"; -import { chmodSync, copyFileSync, existsSync, mkdirSync } from "node:fs"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const root = resolve(__dirname, ".."); - -function run(cmd, args, cwd = root) { - const res = spawnSync(cmd, args, { cwd, stdio: "inherit", shell: false }); - if (res.status !== 0) { - process.exit(res.status ?? 1); - } -} - -function rustHostTriple() { - const res = spawnSync("rustc", ["-vV"], { cwd: root, encoding: "utf8" }); - if (res.status !== 0 || !res.stdout) { - console.error("[core:stage] failed to query rustc host triple"); - process.exit(res.status ?? 1); - } - const line = res.stdout - .split("\n") - .map((s) => s.trim()) - .find((s) => s.startsWith("host:")); - const triple = line?.replace(/^host:\s*/, "").trim(); - if (!triple) { - console.error("[core:stage] rustc host triple missing"); - process.exit(1); - } - return triple; -} - -function cargoTargetDir() { - if (process.env.CARGO_TARGET_DIR) { - // Resolve against the repo root so this path stays consistent - // with the `cargo build` invocation below (which runs with - // `cwd: root`). If the script were invoked from a different - // working directory and `CARGO_TARGET_DIR` were relative, a - // bare `resolve()` would anchor it to the wrong cwd and the - // staged binary lookup would miss. - return resolve(root, process.env.CARGO_TARGET_DIR); - } - const res = spawnSync( - "cargo", - ["metadata", "--format-version", "1", "--no-deps", "--manifest-path", "Cargo.toml"], - { cwd: root, encoding: "utf8", shell: false, maxBuffer: 64 * 1024 * 1024 }, - ); - if (res.status === 0 && res.stdout) { - try { - const meta = JSON.parse(res.stdout); - if (meta.target_directory) return resolve(meta.target_directory); - } catch { - // fall through to default - } - } - return join(root, "target"); -} - -const triple = rustHostTriple(); -const isWindows = process.platform === "win32"; -const binName = isWindows ? "openhuman-core.exe" : "openhuman-core"; - -console.log( - `[core:stage] Building openhuman-core standalone binary for ${triple}...`, -); -run("cargo", [ - "build", - "--manifest-path", - "Cargo.toml", - "--bin", - "openhuman-core", - "--features", - "whatsapp-web,channel-matrix", -]); - -const targetDir = cargoTargetDir(); -const source = join(targetDir, "debug", binName); -if (!existsSync(source)) { - console.error(`[core:stage] compiled binary not found: ${source}`); - process.exit(1); -} - -const outputDir = join(root, "app", "src-tauri", "binaries"); -mkdirSync(outputDir, { recursive: true }); -const sidecarName = isWindows - ? `openhuman-core-${triple}.exe` - : `openhuman-core-${triple}`; -const dest = join(outputDir, sidecarName); -copyFileSync(source, dest); -if (!isWindows) { - chmodSync(dest, 0o755); -} - -console.log(`[core:stage] Staged sidecar: ${dest}`); - -// macOS: sign with a stable local dev certificate so macOS TCC uses certificate -// identity (stable across rebuilds) instead of binary content hash (changes -// every compile). Without this, each recompile breaks existing TCC grants. -if (process.platform === "darwin") { - const DEV_IDENTITY = "OpenHuman Dev Signer"; - const check = spawnSync( - "bash", - ["-c", `security find-identity -v -p codesigning 2>/dev/null | grep "${DEV_IDENTITY}" || true`], - { cwd: root, encoding: "utf8" }, - ); - if (check.stdout && check.stdout.includes(DEV_IDENTITY)) { - const signResult = spawnSync("codesign", ["--force", "--sign", DEV_IDENTITY, "--timestamp=none", dest], { cwd: root, stdio: "inherit", shell: false }); - const isCI = process.env.CI === "true" || process.env.CI === "1"; - if (signResult.status === 0) { - console.log(`[core:stage] Signed sidecar with "${DEV_IDENTITY}"`); - } else if (isCI) { - console.error(`[core:stage] Dev signing failed (status ${signResult.status}) in CI — aborting.`); - process.exit(signResult.status ?? 1); - } else { - console.warn(`[core:stage] Dev signing failed (status ${signResult.status}), continuing without stable signing.`); - } - } else { - console.warn( - `[core:stage] Dev signing identity "${DEV_IDENTITY}" not found.\n` + - `[core:stage] Run 'bash scripts/setup-dev-codesign.sh' once to enable stable TCC grants.\n` + - `[core:stage] Without signing, macOS accessibility grants break on every recompile.`, - ); - } -}