Add CI/CD pipeline for releases (#3)

This commit is contained in:
Thorsten Sommer 2024-06-23 19:33:21 +02:00 committed by GitHub
parent 6d0002ac3b
commit 329467123b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 1599 additions and 76 deletions

26
.gitattributes vendored
View File

@ -1,13 +1,13 @@
*.gif filter=lfs diff=lfs merge=lfs -text media/**/*.gif filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text media/**/*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text media/**/*.jpeg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text media/**/*.ai filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text media/**/*.psd filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text media/**/*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text media/**/*.ogg filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text media/**/*.docx filter=lfs diff=lfs merge=lfs -text
*.docx filter=lfs diff=lfs merge=lfs -text media/**/*.xlsx filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text media/**/*.pptx filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text media/**/*.png filter=lfs diff=lfs merge=lfs -text
*.icns filter=lfs diff=lfs merge=lfs -text media/**/*.ico filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text media/**/*.icns filter=lfs diff=lfs merge=lfs -text

14
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,14 @@
# The default rule is that the maintainers are responsible for everything:
* @MindWorkAI/maintainer
# The release team is responsible for anything inside the .github directory, such as workflows, actions, and issue templates:
/.github/ @MindWorkAI/release
# The release team is responsible for the update directory:
/.updates/ @MindWorkAI/release
# Our Rust experts are responsible for the Rust codebase:
/runtime/ @MindWorkAI/rust-experts
# Our .NET experts are responsible for the .NET codebase:
/app/ @MindWorkAI/net-experts

852
.github/workflows/build-and-release.yml vendored Normal file
View File

@ -0,0 +1,852 @@
name: Build and Release
on:
push:
tags:
- "v*.*.*"
env:
RETENTION_INTERMEDIATE_ASSETS: 1
RETENTION_RELEASE_ASSETS: 30
jobs:
read_metadata:
name: Read metadata
runs-on: ubuntu-latest
outputs:
formatted_version: ${{ steps.format_metadata.outputs.formatted_version }}
formatted_build_time: ${{ steps.format_metadata.outputs.formatted_build_time }}
changelog: ${{ steps.read_changelog.outputs.changelog }}
version: ${{ steps.format_metadata.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Read and format metadata
id: format_metadata
run: |
# Read the first two lines of the metadata file:
version=$(sed -n '1p' metadata.txt)
build_time=$(sed -n '2p' metadata.txt)
# Format the version:
formatted_version="v${version}"
# Format the build time according to RFC 3339:
formatted_build_time=$(date -d "${build_time}" --utc +'%Y-%m-%dT%H:%M:%SZ')
# Log the formatted metadata:
echo "Formatted version: '${formatted_version}'"
echo "Formatted build time: '${formatted_build_time}'"
# Set the outputs:
echo "formatted_version=${formatted_version}" >> "$GITHUB_OUTPUT"
echo "FORMATTED_VERSION=${formatted_version}" >> $GITHUB_ENV
echo "formatted_build_time=${formatted_build_time}" >> "$GITHUB_OUTPUT"
echo "version=${version}" >> "$GITHUB_OUTPUT"
- name: Check tag vs. metadata version
run: |
# Ensure, that the tag matches the version in the metadata file:
if [ "${GITHUB_REF}" != "refs/tags/${FORMATTED_VERSION}" ]; then
echo "Tag '${GITHUB_REF}' does not match the version in the metadata file '${FORMATTED_VERSION}'"
exit 1
else
echo "Tag '${GITHUB_REF}' matches the version in the metadata file '${FORMATTED_VERSION}'"
fi
- name: Read changelog
id: read_changelog
run: |
# Ensure, that the matching changelog file for the current version exists:
if [ ! -f "app/MindWork AI Studio/wwwroot/changelog/${FORMATTED_VERSION}.md" ]; then
echo "Changelog file 'app/MindWork AI Studio/wwwroot/changelog/${FORMATTED_VERSION}.md' not found"
exit 1
else
echo "Changelog file '${FORMATTED_VERSION}.md' found"
fi
# Read the changelog file:
changelog=$(cat "app/MindWork AI Studio/wwwroot/changelog/${FORMATTED_VERSION}.md")
# Set the output:
echo "changelog<<EOOOF" >> "$GITHUB_OUTPUT"
echo "${changelog}" >> "$GITHUB_OUTPUT"
echo "EOOOF" >> "$GITHUB_OUTPUT"
build_main:
name: Build app (${{ matrix.dotnet_runtime }})
needs: read_metadata
strategy:
fail-fast: true
matrix:
include:
- platform: 'macos-latest' # for ARM-based macOS (M1 and above)
rust_target: 'aarch64-apple-darwin'
dotnet_runtime: 'osx-arm64'
dotnet_name_postfix: '-aarch64-apple-darwin'
tauri_bundle: 'dmg updater'
- platform: 'macos-latest' # for Intel-based macOS
rust_target: 'x86_64-apple-darwin'
dotnet_runtime: 'osx-x64'
dotnet_name_postfix: '-x86_64-apple-darwin'
tauri_bundle: 'dmg updater'
- platform: 'ubuntu-22.04' # for x86-based Linux
rust_target: 'x86_64-unknown-linux-gnu'
dotnet_runtime: 'linux-x64'
dotnet_name_postfix: '-x86_64-unknown-linux-gnu'
tauri_bundle: 'appimage deb updater'
- platform: 'windows-latest' # for x86-based Windows
rust_target: 'x86_64-pc-windows-msvc'
dotnet_runtime: 'win-x64'
dotnet_name_postfix: '-x86_64-pc-windows-msvc.exe'
tauri_bundle: 'nsis updater'
- platform: 'windows-latest' # for ARM-based Windows
rust_target: 'aarch64-pc-windows-msvc'
dotnet_runtime: 'win-arm64'
dotnet_name_postfix: '-aarch64-pc-windows-msvc.exe'
tauri_bundle: 'nsis updater'
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: false
- name: Read and format metadata (Unix)
if: matrix.platform != 'windows-latest'
run: |
# Read the lines of the metadata file:
app_version=$(sed -n '1p' metadata.txt)
build_time=$(sed -n '2p' metadata.txt)
build_number=$(sed -n '3p' metadata.txt)
# Next line is the .NET SDK version.
# The format is '8.0.205 (commit 3e1383b780)'.
# We extract only the version number, though:
dotnet_sdk_version=$(sed -n '4p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the .NET runtime version.
# The format is '8.0.5 (commit 087e15321b)'.
# We extract only the version number, though:
dotnet_runtime_version=$(sed -n '5p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the Rust version.
# The format is '1.78.0 (commit 9b00956e5)'.
# We extract only the version number, though:
rust_version=$(sed -n '6p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the MudBlazor version:
mud_blazor_version=$(sed -n '7p' metadata.txt)
# Next line is the Tauri version:
tauri_version=$(sed -n '8p' metadata.txt)
# Format the app version:
formatted_app_version="v${app_version}"
# Write the metadata to the environment:
echo "APP_VERSION=${app_version}" >> $GITHUB_ENV
echo "FORMATTED_APP_VERSION=${formatted_app_version}" >> $GITHUB_ENV
echo "BUILD_TIME=${build_time}" >> $GITHUB_ENV
echo "BUILD_NUMBER=${build_number}" >> $GITHUB_ENV
echo "DOTNET_SDK_VERSION=${dotnet_sdk_version}" >> $GITHUB_ENV
echo "DOTNET_RUNTIME_VERSION=${dotnet_runtime_version}" >> $GITHUB_ENV
echo "RUST_VERSION=${rust_version}" >> $GITHUB_ENV
echo "MUD_BLAZOR_VERSION=${mud_blazor_version}" >> $GITHUB_ENV
echo "TAURI_VERSION=${tauri_version}" >> $GITHUB_ENV
# Log the metadata:
echo "App version: '${formatted_app_version}'"
echo "Build time: '${build_time}'"
echo "Build number: '${build_number}'"
echo ".NET SDK version: '${dotnet_sdk_version}'"
echo ".NET runtime version: '${dotnet_runtime_version}'"
echo "Rust version: '${rust_version}'"
echo "MudBlazor version: '${mud_blazor_version}'"
echo "Tauri version: '${tauri_version}'"
- name: Read and format metadata (Windows)
if: matrix.platform == 'windows-latest'
run: |
# Read the lines of the metadata file:
$metadata = Get-Content metadata.txt
$app_version = $metadata[0]
$build_time = $metadata[1]
$build_number = $metadata[2]
# Next line is the .NET SDK version.
# The format is '8.0.205 (commit 3e1383b780)'.
# We extract only the version number, though:
$dotnet_sdk_version = ($metadata[3] -match '(\d+\.\d+\.\d+)') | Out-Null; $dotnet_sdk_version = $matches[1]
# Next line is the .NET runtime version.
# The format is '8.0.5 (commit 087e15321b)'.
# We extract only the version number, though:
$dotnet_runtime_version = ($metadata[4] -match '(\d+\.\d+\.\d+)') | Out-Null; $dotnet_runtime_version = $matches[1]
# Next line is the Rust version.
# The format is '1.78.0 (commit 9b00956e5)'.
# We extract only the version number, though:
$rust_version = ($metadata[5] -match '(\d+\.\d+\.\d+)') | Out-Null; $rust_version = $matches[1]
$mud_blazor_version = $metadata[6]
$tauri_version = $metadata[7]
# Format the app version:
$formatted_app_version = "v${app_version}"
# Write the metadata to the environment:
Write-Output "APP_VERSION=${app_version}" >> $env:GITHUB_ENV
Write-Output "FORMATTED_APP_VERSION=${formatted_app_version}" >> $env:GITHUB_ENV
Write-Output "BUILD_TIME=${build_time}" >> $env:GITHUB_ENV
Write-Output "BUILD_NUMBER=${build_number}" >> $env:GITHUB_ENV
Write-Output "DOTNET_SDK_VERSION=${dotnet_sdk_version}" >> $env:GITHUB_ENV
Write-Output "DOTNET_RUNTIME_VERSION=${dotnet_runtime_version}" >> $env:GITHUB_ENV
Write-Output "RUST_VERSION=${rust_version}" >> $env:GITHUB_ENV
Write-Output "MUD_BLAZOR_VERSION=${mud_blazor_version}" >> $env:GITHUB_ENV
# Log the metadata:
Write-Output "App version: '${formatted_app_version}'"
Write-Output "Build time: '${build_time}'"
Write-Output "Build number: '${build_number}'"
Write-Output ".NET SDK version: '${dotnet_sdk_version}'"
Write-Output ".NET runtime version: '${dotnet_runtime_version}'"
Write-Output "Rust version: '${rust_version}'"
Write-Output "MudBlazor version: '${mud_blazor_version}'"
Write-Output "Tauri version: '${tauri_version}'"
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
cache: true
cache-dependency-path: 'app/MindWork AI Studio/packages.lock.json'
- name: Build .NET project
run: |
cd "app/MindWork AI Studio"
dotnet publish --configuration release --runtime ${{ matrix.dotnet_runtime }} --disable-build-servers --force --output ../../publish/dotnet
- name: Move & rename .NET artifact (Unix)
if: matrix.platform != 'windows-latest'
run: |
mkdir -p "app/MindWork AI Studio/bin/dist"
cd publish/dotnet
mv mindworkAIStudio "../../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer${{ matrix.dotnet_name_postfix }}"
- name: Move & rename .NET artifact (Windows)
if: matrix.platform == 'windows-latest'
run: |
New-Item -ItemType Directory -Path "app\MindWork AI Studio\bin\dist" -Force
cd publish/dotnet
mv mindworkAIStudio.exe "../../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer${{ matrix.dotnet_name_postfix }}"
- name: Create parts for the Rust cache key (Unix)
if: matrix.platform != 'windows-latest'
run: |
cd runtime
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $GITHUB_ENV
- name: Create parts for the Rust cache key (Windows)
if: matrix.platform == 'windows-latest'
run: |
cd runtime
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $env:GITHUB_ENV
- name: Cache Rust
uses: actions/cache@v4
with:
path: |
~/.cargo/bin
~/.cargo/git/db/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.rustup/toolchains
runtime/target
# When the entire key matches, Rust might just create the bundles using the current .NET build:
key: target-${{ matrix.dotnet_runtime }}-rust-${{ env.RUST_VERSION }}-dependencies-${{ env.CARGO_LOCK_HASH }}
# - 1st key: the Rust runtime dependencies changed. Anyway, we might be able to re-use many previously built packages.
#
# - No match: alright, a new Rust version was released. Sadly, we cannot re-use anything now. Why?
# The updated Rust compiler might mitigate some bugs or vulnerabilities. In order to apply
# these changes to our app, we have to re-compile everything. That's the reason why it makes
# no sense to use more parts for the cache key, like Tauri or Tauri build versions.
restore-keys: |
target-${{ matrix.dotnet_runtime }}-rust-${{ env.RUST_VERSION }}-dependencies-
- name: Setup Rust (stable)
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
targets: ${{ matrix.rust_target }}
- name: Setup dependencies (Ubuntu-specific, x86)
if: matrix.platform == 'ubuntu-22.04' && contains(matrix.rust_target, 'x86_64')
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: Setup Tauri (Unix)
if: matrix.platform != 'windows-latest'
run: |
if ! cargo tauri --version > /dev/null 2>&1; then
cargo install tauri-cli
else
echo "Tauri is already installed"
fi
- name: Setup Tauri (Windows)
if: matrix.platform == 'windows-latest'
run: |
if (-not (cargo tauri --version 2>$null)) {
cargo install tauri-cli
} else {
Write-Output "Tauri is already installed"
}
- name: Build Tauri project (Unix)
if: matrix.platform != 'windows-latest'
env:
PRIVATE_PUBLISH_KEY: ${{ secrets.PRIVATE_PUBLISH_KEY }}
PRIVATE_PUBLISH_KEY_PASSWORD: ${{ secrets.PRIVATE_PUBLISH_KEY_PASSWORD }}
run: |
cd runtime
export TAURI_PRIVATE_KEY="$PRIVATE_PUBLISH_KEY"
export TAURI_KEY_PASSWORD="$PRIVATE_PUBLISH_KEY_PASSWORD"
cargo tauri build --target ${{ matrix.rust_target }} --bundles ${{ matrix.tauri_bundle }}
- name: Build Tauri project (Windows)
if: matrix.platform == 'windows-latest'
env:
PRIVATE_PUBLISH_KEY: ${{ secrets.PRIVATE_PUBLISH_KEY }}
PRIVATE_PUBLISH_KEY_PASSWORD: ${{ secrets.PRIVATE_PUBLISH_KEY_PASSWORD }}
run: |
cd runtime
$env:TAURI_PRIVATE_KEY="$env:PRIVATE_PUBLISH_KEY"
$env:TAURI_KEY_PASSWORD="$env:PRIVATE_PUBLISH_KEY_PASSWORD"
cargo tauri build --target ${{ matrix.rust_target }} --bundles ${{ matrix.tauri_bundle }}
- name: Upload artifact (macOS)
if: startsWith(matrix.platform, 'macos')
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (macOS ${{ matrix.dotnet_runtime }})
path: |
runtime/target/${{ matrix.rust_target }}/release/bundle/dmg/MindWork AI Studio_*.dmg
runtime/target/${{ matrix.rust_target }}/release/bundle/macos/MindWork AI Studio.app.tar.gz*
if-no-files-found: error
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
- name: Upload artifact (Windows - MSI)
if: startsWith(matrix.platform, 'windows') && contains(matrix.tauri_bundle, 'msi')
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (Windows - MSI ${{ matrix.dotnet_runtime }})
path: |
runtime/target/${{ matrix.rust_target }}/release/bundle/msi/MindWork AI Studio_*.msi
runtime/target/${{ matrix.rust_target }}/release/bundle/msi/MindWork AI Studio*msi.zip*
if-no-files-found: error
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
- name: Upload artifact (Windows - NSIS)
if: startsWith(matrix.platform, 'windows') && contains(matrix.tauri_bundle, 'nsis')
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (Windows - NSIS ${{ matrix.dotnet_runtime }})
path: |
runtime/target/${{ matrix.rust_target }}/release/bundle/nsis/MindWork AI Studio_*.exe
runtime/target/${{ matrix.rust_target }}/release/bundle/nsis/MindWork AI Studio*nsis.zip*
if-no-files-found: error
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
- name: Upload artifact (Linux - Debian Package)
if: startsWith(matrix.platform, 'ubuntu') && contains(matrix.tauri_bundle, 'deb')
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (Linux - deb ${{ matrix.dotnet_runtime }})
path: |
runtime/target/${{ matrix.rust_target }}/release/bundle/deb/mind-work-ai-studio_*.deb
if-no-files-found: error
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
- name: Upload artifact (Linux - AppImage)
if: startsWith(matrix.platform, 'ubuntu') && contains(matrix.tauri_bundle, 'appimage')
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (Linux - AppImage ${{ matrix.dotnet_runtime }})
path: |
runtime/target/${{ matrix.rust_target }}/release/bundle/appimage/mind-work-ai-studio_*.AppImage
runtime/target/${{ matrix.rust_target }}/release/bundle/appimage/mind-work-ai-studio*AppImage.tar.gz*
if-no-files-found: error
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
build_linux_arm64:
name: Build app (linux-arm64)
runs-on: ubuntu-latest
needs: read_metadata
env:
SKIP: false # allows disabling this long-running job temporarily
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: false
- name: Read and format metadata
if: ${{ env.SKIP != 'true' }}
id: metadata
run: |
# Read the lines of the metadata file:
app_version=$(sed -n '1p' metadata.txt)
build_time=$(sed -n '2p' metadata.txt)
build_number=$(sed -n '3p' metadata.txt)
# Next line is the .NET SDK version.
# The format is '8.0.205 (commit 3e1383b780)'.
# We extract only the version number, though:
dotnet_sdk_version=$(sed -n '4p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the .NET runtime version.
# The format is '8.0.5 (commit 087e15321b)'.
# We extract only the version number, though:
dotnet_runtime_version=$(sed -n '5p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the Rust version.
# The format is '1.78.0 (commit 9b00956e5)'.
# We extract only the version number, though:
rust_version=$(sed -n '6p' metadata.txt | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
# Next line is the MudBlazor version:
mud_blazor_version=$(sed -n '7p' metadata.txt)
# Next line is the Tauri version:
tauri_version=$(sed -n '8p' metadata.txt)
# Format the app version:
formatted_app_version="v${app_version}"
# Write the metadata to the environment:
echo "APP_VERSION=${app_version}" >> $GITHUB_ENV
echo "FORMATTED_APP_VERSION=${formatted_app_version}" >> $GITHUB_ENV
echo "BUILD_TIME=${build_time}" >> $GITHUB_ENV
echo "BUILD_NUMBER=${build_number}" >> $GITHUB_ENV
echo "DOTNET_SDK_VERSION=${dotnet_sdk_version}" >> $GITHUB_ENV
echo "DOTNET_RUNTIME_VERSION=${dotnet_runtime_version}" >> $GITHUB_ENV
echo "RUST_VERSION=${rust_version}" >> $GITHUB_ENV
echo "MUD_BLAZOR_VERSION=${mud_blazor_version}" >> $GITHUB_ENV
echo "TAURI_VERSION=${tauri_version}" >> $GITHUB_ENV
# Log the metadata:
echo "App version: '${formatted_app_version}'"
echo "Build time: '${build_time}'"
echo "Build number: '${build_number}'"
echo ".NET SDK version: '${dotnet_sdk_version}'"
echo ".NET runtime version: '${dotnet_runtime_version}'"
echo "Rust version: '${rust_version}'"
echo "MudBlazor version: '${mud_blazor_version}'"
echo "Tauri version: '${tauri_version}'"
- name: Setup .NET
if: ${{ env.SKIP != 'true' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSI }}
cache: true
cache-dependency-path: 'app/MindWork AI Studio/packages.lock.json'
- name: Build .NET project
if: ${{ env.SKIP != 'true' }}
run: |
cd "app/MindWork AI Studio"
dotnet publish --configuration release --runtime linux-arm64 --disable-build-servers --force --output ../../publish/dotnet
- name: Move & rename the .NET artifact
if: ${{ env.SKIP != 'true' }}
run: |
mkdir -p "app/MindWork AI Studio/bin/dist"
cd publish/dotnet
mv mindworkAIStudio "../../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer-aarch64-unknown-linux-gnu"
- name: Create parts for the Rust cache key
if: ${{ env.SKIP != 'true' }}
run: |
cd runtime
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $GITHUB_ENV
- name: Cache linux arm64 runner image
if: ${{ env.SKIP != 'true' }}
uses: actions/cache@v4
id: linux_arm_cache
with:
path: $RUNNER_TEMP/linux_arm_qemu_cache.img
# When the entire key matches, Rust might just create the bundles using the current .NET build:
key: target-linux-arm64-rust-${{ env.RUST_VERSION }}-dependencies-${{ env.CARGO_LOCK_HASH }}
# - 1st key: the Rust runtime dependencies changed. Anyway, we might be able to re-use many previously built packages.
#
# - No match: alright, a new Rust version was released. Sadly, we cannot re-use anything now. Why?
# The updated Rust compiler might mitigate some bugs or vulnerabilities. In order to apply
# these changes to our app, we have to re-compile everything. That's the reason why it makes
# no sense to use more parts for the cache key, like Tauri or Tauri build versions.
restore-keys: |
target-linux-arm64-rust-${{ env.RUST_VERSION }}-dependencies-
- name: Build linux arm runner image
uses: pguyot/arm-runner-action@v2
id: build-linux-arm-runner
if: ${{ steps.linux_arm_cache.outputs.cache-hit != 'true' && env.SKIP != 'true' }}
env:
RUST_VERSION: ${{ env.RUST_VERSION }}
TAURI_VERSION: ${{ env.TAURI_VERSION }}
with:
base_image: dietpi:rpi_armv8_bullseye
cpu: cortex-a53
image_additional_mb: 6000 # ~ 6GB
optimize_image: false
shell: /bin/bash
commands: |
# Rust complains (rightly) that $HOME doesn't match eid home:
export HOME=/root
# Workaround to CI worker being stuck on Updating crates.io index:
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
# Update and upgrade the system:
apt-get update --yes --allow-releaseinfo-change
apt-get upgrade --yes
apt-get autoremove --yes
apt-get install curl wget --yes
# Install Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y
source "$HOME/.cargo/env"
rustup toolchain install $RUST_VERSION
# Install build tools and tauri-cli requirements:
apt-get install --yes libwebkit2gtk-4.0-dev build-essential libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
# Setup Tauri:
cargo install tauri-cli
- name: Add the built runner image to the cache
if: ${{ steps.linux_arm_cache.outputs.cache-hit != 'true' && env.SKIP != 'true' }}
run: |
mv ${{ steps.build-linux-arm-runner.outputs.image }} $RUNNER_TEMP/linux_arm_qemu_cache.img
- name: Build Tauri project
if: ${{ env.SKIP != 'true' }}
uses: pguyot/arm-runner-action@v2
id: build-linux-arm
with:
base_image: file://$RUNNER_TEMP/linux_arm_qemu_cache.img
cpu: cortex-a53
optimize_image: false
copy_artifact_path: runtime
copy_artifact_dest: result
#
# We do not need to set the PRIVATE_PUBLISH_KEY and PRIVATE_PUBLISH_KEY_PASSWORD here,
# because we cannot produce the AppImage on arm64. Only the AppImage supports the automatic
# update feature. The Debian package does not support this feature.
#
#PRIVATE_PUBLISH_KEY: ${{ secrets.PRIVATE_PUBLISH_KEY }}
#PRIVATE_PUBLISH_KEY_PASSWORD: ${{ secrets.PRIVATE_PUBLISH_KEY_PASSWORD }}
#
shell: /bin/bash
commands: |
export HOME=/root
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
source "$HOME/.cargo/env"
cd runtime
cargo tauri build --target aarch64-unknown-linux-gnu --bundles deb
- name: Debug
if: ${{ env.SKIP != 'true' }}
run: |
echo "Current directory: $(pwd)"
ls -lhat
echo "Searching for linux_arm_qemu_cache.img"
find $RUNNER_TEMP -name 'linux_arm_qemu_cache.img' -print 2>/dev/null
echo "Searching for mind-work-ai-studio_*.deb"
find . -name 'mind-work-ai-studio_*.deb' -print 2>/dev/null
- name: Update the runner image to cache the Rust runtime build
if: ${{ env.SKIP != 'true' }}
run: |
mv ${{ steps.build-linux-arm.outputs.image }} $RUNNER_TEMP/linux_arm_qemu_cache.img
- name: Upload artifact (Linux - Debian Package)
if: ${{ env.SKIP != 'true' }}
uses: actions/upload-artifact@v4
with:
name: MindWork AI Studio (Linux - deb linux-arm64)
path: |
result/target/aarch64-unknown-linux-gnu/release/bundle/deb/mind-work-ai-studio_*.deb
if-no-files-found: warn
retention-days: ${{ env.RETENTION_INTERMEDIATE_ASSETS }}
create_release:
name: Prepare & create release
runs-on: ubuntu-latest
needs: [build_main, read_metadata, build_linux_arm64]
steps:
- name: Create artifact directory
run: mkdir -p $GITHUB_WORKSPACE/artifacts
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ${{ github.workspace }}/artifacts
merge-multiple: false
- name: Display structure of previously artifacts
run: ls -Rlhat $GITHUB_WORKSPACE/artifacts
- name: Prepare release assets
env:
VERSION: ${{ needs.read_metadata.outputs.version }}
run: |
RELEASE_DIR="$GITHUB_WORKSPACE/release/assets"
# Ensure the release directory exists:
mkdir -p "$RELEASE_DIR"
# Find and process files in the artifacts directory:
find "$GITHUB_WORKSPACE/artifacts" -type f | while read -r FILE; do
if [[ "$FILE" == *"osx-x64"* && "$FILE" == *".tar.gz" ]]; then
TARGET_NAME="MindWork AI Studio_x64.app.tar.gz"
elif [[ "$FILE" == *"osx-x64"* && "$FILE" == *".tar.gz.sig" ]]; then
TARGET_NAME="MindWork AI Studio_x64.app.tar.gz.sig"
elif [[ "$FILE" == *"osx-arm64"* && "$FILE" == *".tar.gz" ]]; then
TARGET_NAME="MindWork AI Studio_aarch64.app.tar.gz"
elif [[ "$FILE" == *"osx-arm64"* && "$FILE" == *".tar.gz.sig" ]]; then
TARGET_NAME="MindWork AI Studio_aarch64.app.tar.gz.sig"
else
TARGET_NAME="$(basename "$FILE")"
TARGET_NAME=$(echo "$TARGET_NAME" | sed "s/_${VERSION}//")
fi
cp "$FILE" "${RELEASE_DIR}/${TARGET_NAME}"
done
# Display the structure of the release directory:
ls -Rlhat $GITHUB_WORKSPACE/release/assets
- name: Create .update directory
run: mkdir -p $GITHUB_WORKSPACE/.updates
- name: Build platform JSON for latest.json file
env:
FORMATTED_VERSION: ${{ needs.read_metadata.outputs.formatted_version }}
run: |
# Here, we create the JSON object:
platforms_json=$(jq -n '{}')
# Define the urlencode function:
urlencode() {
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
}
# Display the structure of the release directory:
ls -Rlhat $GITHUB_WORKSPACE/release/assets
# Iterate over all signature files:
while IFS= read -r -d '' sig_file; do
echo "Processing signature file '$sig_file':"
#
# Next, we determine the "update platform".
# We store the result in the $platform variable.
#
# We derive the platform from the signature file name:
# - platform=darwin-aarch64 when path contains 'aarch64-apple-darwin'
# - platform=darwin-x86_64 when path contains 'x86_64-apple-darwin'
# - platform=linux-x86_64 when path contains 'x86_64-unknown-linux-'
# - platform=windows-x86_64 when path contains 'x86_64-pc-windows-'
# - platform=windows-aarch64 when path contains 'aarch64-pc-windows-'
#
if [[ "$sig_file" == *"aarch64.app"* ]]; then
platform="darwin-aarch64"
elif [[ "$sig_file" == *"x64.app"* ]]; then
platform="darwin-x86_64"
elif [[ "$sig_file" == *"amd64.AppImage"* ]]; then
platform="linux-x86_64"
elif [[ "$sig_file" == *"x64-setup.nsis"* ]]; then
platform="windows-x86_64"
elif [[ "$sig_file" == *"arm64-setup.nsis"* ]]; then
platform="windows-aarch64"
else
echo "Platform not recognized: '$sig_file'"
exit 1
fi
# Read the signature:
signature=$(cat "$sig_file")
# Extract the artifact name and create the URL:
artifact_name=$(basename "$sig_file" .sig)
encoded_artifact_name=$(urlencode "$artifact_name")
url="https://github.com/MindWorkAI/AI-Studio/releases/download/$FORMATTED_VERSION/$encoded_artifact_name"
# Build the JSON object:
platforms_json=$(echo "$platforms_json" | jq --arg platform "$platform" --arg signature "$signature" --arg url "$url" '.[$platform] = {"signature": $signature, "url": $url}')
done < <(find $GITHUB_WORKSPACE/release/assets -type f -name '*.sig' -print0)
# Write the JSON object to a temporary file:
echo "$platforms_json" > $GITHUB_WORKSPACE/.updates/platforms.json
- name: Create latest.json
env:
FORMATTED_VERSION: ${{ needs.read_metadata.outputs.formatted_version }}
FORMATTED_BUILD_TIME: ${{ needs.read_metadata.outputs.formatted_build_time }}
CHANGELOG: ${{ needs.read_metadata.outputs.changelog }}
run: |
# Read the platforms JSON, which was created in the previous step:
platforms=$(cat $GITHUB_WORKSPACE/.updates/platforms.json)
# Replace newlines in changelog with \n
changelog=$(echo "$CHANGELOG" | awk '{printf "%s\\n", $0}')
# Create the latest.json file:
cat <<EOOOF > $GITHUB_WORKSPACE/release/assets/latest.json
{
"version": "$FORMATTED_VERSION",
"notes": "$changelog",
"pub_date": "$FORMATTED_BUILD_TIME",
"platforms": $platforms
}
EOOOF
- name: Show all release assets
run: ls -Rlhat $GITHUB_WORKSPACE/release/assets
- name: Display the content of latest.json
run: cat $GITHUB_WORKSPACE/release/assets/latest.json
- name: Upload release assets
uses: actions/upload-artifact@v4
env:
FORMATTED_VERSION: ${{ needs.read_metadata.outputs.formatted_version }}
with:
name: MindWork AI Studio ${{ env.FORMATTED_VERSION }} Release
path: release/assets/
if-no-files-found: error
retention-days: ${{ env.RETENTION_RELEASE_ASSETS }}
publish_release:
name: Publish release
runs-on: ubuntu-latest
needs: [read_metadata, create_release]
env:
FORMATTED_VERSION: ${{ needs.read_metadata.outputs.formatted_version }}
CHANGELOG: ${{ needs.read_metadata.outputs.changelog }}
steps:
- name: Create release folder
run: mkdir -p release/assets
- name: Download release assets
uses: actions/download-artifact@v4
with:
name: MindWork AI Studio ${{ env.FORMATTED_VERSION }} Release
path: release/assets
- name: Display the content of the release folder
run: ls -Rlhat release/assets
- name: Scan for threats
id: virus_total
uses: crazy-max/ghaction-virustotal@v4
with:
vt_api_key: ${{ secrets.VIRUS_TOTAL_KEY }}
files: release/assets/*
request_rate: 4
vt_monitor: false
github_token: ${{ secrets.GITHUB_TOKEN }}
update_release_body: true
- name: Append scan results to changelog
run: |
changelog="${{ env.CHANGELOG }}"
links="${{ steps.virus_total.outputs.analysis }}"
# Create a temporary file for the changelog:
temp_changelog=$(mktemp)
# Add the new Markdown section:
echo -e "$changelog" > $temp_changelog
echo -e "\n\n## Virus scans" >> $temp_changelog
# Split the analysis output by comma:
IFS=',' read -ra analysis_array <<< "$links"
# Append each file and link to the changelog:
for item in "${analysis_array[@]}"; do
# Get the part before the first '=':
filename="${item%%=*}"
filename=$(echo $filename | xargs)
# Extract the base name of the file
base_filename=$(basename "$filename")
# Ignore the latest.json file:
if [[ "$base_filename" == "latest.json" ]]; then
continue
fi
# Get the part after the first '=':
link="${item#*=}"
link=$(echo $link | xargs)
# Append this scan result to the changelog:
echo "- [$base_filename]($link)" >> $temp_changelog
done
# Export the modified changelog (using HEREDOC syntax for multi-line support):
echo "CHANGELOG<<EOOOF" >> $GITHUB_ENV
cat $temp_changelog >> $GITHUB_ENV
echo "EOOOF" >> $GITHUB_ENV
- name: Create release
uses: softprops/action-gh-release@v2
with:
prerelease: false
draft: false
make_latest: true
body: ${{ env.CHANGELOG }}
name: "Release ${{ env.FORMATTED_VERSION }}"
fail_on_unmatched_files: true
files: |
release/assets/*

View File

View File

@ -1,4 +1,6 @@
# MindWork AI Studio # MindWork AI Studio
![MindWork AI Studio](documentation/AI%20Studio.png)
MindWork AI Studio is a desktop application available for macOS, Windows, and Linux. It provides a unified chat interface for Large Language Models (LLMs). You bring your own API key for the respective LLM provider to use the models. The API keys are securely stored by the operating system. MindWork AI Studio is a desktop application available for macOS, Windows, and Linux. It provides a unified chat interface for Large Language Models (LLMs). You bring your own API key for the respective LLM provider to use the models. The API keys are securely stored by the operating system.
**Key advantages:** **Key advantages:**
@ -10,7 +12,7 @@ MindWork AI Studio is a desktop application available for macOS, Windows, and Li
- **Flexibility**: Choose the provider and model best suited for your current task. - **Flexibility**: Choose the provider and model best suited for your current task.
- **No bloatware**: The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life. - **No bloatware**: The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life.
**Ready to get started 🤩?** [Download the appropriate setup for your operating system here](https://github.com/MindWorkAI/AI-Studio/releases/latest). **Ready to get started 🤩?** [Download the appropriate setup for your operating system here](documentation/Setup.md).
## Support the Project ## Support the Project
Thank you for using MindWork AI Studio and considering supporting its development 😀. Your support helps keep the project alive and ensures continuous improvements and new features. Thank you for using MindWork AI Studio and considering supporting its development 😀. Your support helps keep the project alive and ensures continuous improvements and new features.
@ -20,7 +22,7 @@ We offer various ways you can support the project:
For companies, sponsoring MindWork AI Studio is not only a way to support innovation but also a valuable opportunity for public relations and marketing. Your company's name and logo will be featured prominently, showcasing your commitment to using cutting-edge AI tools and enhancing your reputation as an innovative enterprise. For companies, sponsoring MindWork AI Studio is not only a way to support innovation but also a valuable opportunity for public relations and marketing. Your company's name and logo will be featured prominently, showcasing your commitment to using cutting-edge AI tools and enhancing your reputation as an innovative enterprise.
To view all available tiers and their specific perks, please visit our [GitHub Sponsors page](https://github.com/MindWorkAI/AI-Studio/blob/main/Sponsors.md). To view all available tiers and their specific perks, please visit our [GitHub Sponsors page](Sponsors.md).
Your support, whether big or small, keeps the wheels turning and is deeply appreciated ❤️. Your support, whether big or small, keeps the wheels turning and is deeply appreciated ❤️.
## Planned Features ## Planned Features
@ -35,19 +37,7 @@ Here's an exciting look at some of the features we're planning to add to MindWor
Stay tuned for more updates and enhancements to make MindWork AI Studio even more powerful and versatile 🤩. Stay tuned for more updates and enhancements to make MindWork AI Studio even more powerful and versatile 🤩.
## Building ## Building
You just want to use the app? Then simply [download the appropriate setup for your operating system](https://github.com/MindWorkAI/AI-Studio/releases/latest). This chapter is intended for developers who want to modify and customize the code. You want to know how to build MindWork AI Studio from source? [Check out the instructions here](documentation/Build.md).
In order to build MindWork AI Studio from source instead of using the pre-built binaries, follow these steps:
1. Install the .NET 8 SDK.
2. Install the Rust compiler.
3. Install NuShell. This shell works on all operating systems and is required because the build script is written in NuShell.
4. Clone the repository.
5. Open a terminal with NuShell.
6. Navigate to the `/app/MindWork AI Studio` directory within the repository.
7. To build the current version, run `nu build.nu publish`.
- This will build the app for the current operating system, for both x64 (Intel, AMD) and ARM64 (e.g., Apple Silicon, Raspberry Pi).
- The setup program will be located in `runtime/target/release/bundle` afterward.
8. To prepare a new release, run `nu build.nu prepare <ACTION>`, where `<ACTION>` is either `patch`, `minor`, or `major`.
## License ## License
MindWork AI Studio is licensed under the `FSL-1.1-MIT` license (functional source license). Heres a simple rundown of what that means for you: MindWork AI Studio is licensed under the `FSL-1.1-MIT` license (functional source license). Heres a simple rundown of what that means for you:
@ -56,4 +46,4 @@ MindWork AI Studio is licensed under the `FSL-1.1-MIT` license (functional sourc
- **No Warranties**: The software is provided "as is", without any promises from us about it working perfectly for your needs. While we strive to make it great, we can't guarantee it will be free of bugs or issues. - **No Warranties**: The software is provided "as is", without any promises from us about it working perfectly for your needs. While we strive to make it great, we can't guarantee it will be free of bugs or issues.
- **Future License**: Good news! The license for each release of MindWork AI Studio will automatically convert to an MIT license two years from its release date. This makes it even easier for you to use the software in the future. - **Future License**: Good news! The license for each release of MindWork AI Studio will automatically convert to an MIT license two years from its release date. This makes it even easier for you to use the software in the future.
For more details, refer to the [LICENSE](LICENSE) file. This license structure ensures you have plenty of freedom to use and enjoy the software while protecting our work. For more details, refer to the [LICENSE](LICENSE.md) file. This license structure ensures you have plenty of freedom to use and enjoy the software while protecting our work.

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsonSchemaMappingsProjectConfiguration">
<state>
<map>
<entry key="GitHub Workflow">
<value>
<SchemaInfo>
<option name="name" value="GitHub Workflow" />
<option name="relativePathToSchema" value="https://json.schemastore.org/github-workflow.json" />
<option name="applicationDefined" value="true" />
<option name="patterns">
<list>
<Item>
<option name="path" value="file://$PROJECT_DIR$/../.github/workflows/build-and-release.yml" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
</map>
</state>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="TaskProjectConfiguration">
<server type="Gitlab" url="https://devops.tsommer.org" />
</component>
</project>

View File

@ -13,7 +13,7 @@
<MudListItem Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/> <MudListItem Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/>
<MudListItem Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/> <MudListItem Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/> <MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnet"/> <MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnetRuntime"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/> <MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/>
<MudListItem Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/> <MudListItem Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/> <MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>

View File

@ -9,7 +9,7 @@ public partial class About : ComponentBase
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly(); private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!; private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!;
private static string VersionDotnet => $"Used .NET compiler: v{META_DATA.DotnetVersion}"; private static string VersionDotnetRuntime => $"Used .NET runtime: v{META_DATA.DotnetVersion}";
private static string VersionDotnetSdk => $"Used .NET SDK: v{META_DATA.DotnetSdkVersion}"; private static string VersionDotnetSdk => $"Used .NET SDK: v{META_DATA.DotnetSdkVersion}";

View File

@ -16,6 +16,7 @@
<SelfContained>true</SelfContained> <!-- Publish as self-contained; requires no .NET runtime installed on the target machine --> <SelfContained>true</SelfContained> <!-- Publish as self-contained; requires no .NET runtime installed on the target machine -->
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> <!-- Include native libraries for self-extract --> <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> <!-- Include native libraries for self-extract -->
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> <!-- Generate embedded files manifest --> <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> <!-- Generate embedded files manifest -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <!-- Restore packages with lock file; needed for caching NuGet packages-->
<PublishTrimmed>true</PublishTrimmed> <!-- Publish with trimming, to reduce size --> <PublishTrimmed>true</PublishTrimmed> <!-- Publish with trimming, to reduce size -->
<TrimMode>partial</TrimMode> <!-- Trim unused assemblies, but keep all assemblies referenced by the project --> <TrimMode>partial</TrimMode> <!-- Trim unused assemblies, but keep all assemblies referenced by the project -->
@ -44,9 +45,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.5" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.6" />
<PackageReference Include="MudBlazor" Version="6.19.1" /> <PackageReference Include="MudBlazor" Version="6.20.0" />
<PackageReference Include="MudBlazor.Markdown" Version="1.0.0" /> <PackageReference Include="MudBlazor.Markdown" Version="1.0.2" />
</ItemGroup> </ItemGroup>
<!-- Read the meta data file --> <!-- Read the meta data file -->

View File

@ -42,7 +42,7 @@ def "main metadata" []: nothing -> nothing {
update_mudblazor_version update_mudblazor_version
update_tauri_version update_tauri_version
update_project_commit_hash update_project_commit_hash
update_license_year "../../LICENSE" update_license_year "../../LICENSE.md"
update_license_year "Components/Pages/About.razor.cs" update_license_year "Components/Pages/About.razor.cs"
} }
@ -96,12 +96,12 @@ def "main publish" []: nothing -> nothing {
^dotnet publish --configuration release --runtime $rid --disable-build-servers --force ^dotnet publish --configuration release --runtime $rid --disable-build-servers --force
let final_filename = match $rid { let final_filename = match $rid {
"win-x64" => "mindworkAIStudio-x86_64-pc-windows-msvc.exe", "win-x64" => "mindworkAIStudioServer-x86_64-pc-windows-msvc.exe",
"win-arm64" => "mindworkAIStudio-aarch64-pc-windows-msvc.exe", "win-arm64" => "mindworkAIStudioServer-aarch64-pc-windows-msvc.exe",
"linux-x64" => "mindworkAIStudio-x86_64-unknown-linux-gnu", "linux-x64" => "mindworkAIStudioServer-x86_64-unknown-linux-gnu",
"linux-arm64" => "mindworkAIStudio-aarch64-unknown-linux-gnu", "linux-arm64" => "mindworkAIStudioServer-aarch64-unknown-linux-gnu",
"osx-arm64" => "mindworkAIStudio-aarch64-apple-darwin", "osx-arm64" => "mindworkAIStudioServer-aarch64-apple-darwin",
"osx-x64" => "mindworkAIStudio-x86_64-apple-darwin", "osx-x64" => "mindworkAIStudioServer-x86_64-apple-darwin",
_ => { _ => {
print $"Unsupported RID for final filename: ($rid)" print $"Unsupported RID for final filename: ($rid)"
@ -128,7 +128,7 @@ def "main publish" []: nothing -> nothing {
cd ../../runtime cd ../../runtime
try { try {
cargo tauri build cargo tauri build --bundles none
}; };
cd "../app/MindWork AI Studio" cd "../app/MindWork AI Studio"

View File

@ -0,0 +1,168 @@
{
"version": 1,
"dependencies": {
"net8.0": {
"Microsoft.Extensions.FileProviders.Embedded": {
"type": "Direct",
"requested": "[8.0.6, )",
"resolved": "8.0.6",
"contentHash": "hQlf5+YxiUbKdpaPBf/zdMGItnWF8ai9ToPjeZ6gnxT10V4RGDKvChl5MSdc838+2SRHLAC0cdJwG0+L7dqR0g==",
"dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
}
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.6, )",
"resolved": "8.0.6",
"contentHash": "E+lDylsTeP4ZiDmnEkiJ5wobnGaIJzFhOgZppznJCb69UZgbh6G3cfv1pnLDLLBx6JAgl0kAlnINDeT3uCuczQ=="
},
"MudBlazor": {
"type": "Direct",
"requested": "[6.20.0, )",
"resolved": "6.20.0",
"contentHash": "2MqW/E1OLszSqDhW06rpRTN4OpIRJU0iVzeiZLPzymckrKJH1Hg09St+O3kaEnsbXRcjcdM9iE5cSKzCgxvySQ==",
"dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3",
"Microsoft.AspNetCore.Components.Web": "8.0.3",
"Microsoft.Extensions.Localization": "8.0.3"
}
},
"MudBlazor.Markdown": {
"type": "Direct",
"requested": "[1.0.2, )",
"resolved": "1.0.2",
"contentHash": "yXEuF1XTtZy0XkxDVXj9Jd8chwsNwu1IaDpb7FsbZWU8sMg1zCk+GXZdTSKH+C0blHJEDEOl5bzp3JU1S/737w==",
"dependencies": {
"Markdig": "0.37.0",
"MudBlazor": "6.20.0"
}
},
"Markdig": {
"type": "Transitive",
"resolved": "0.37.0",
"contentHash": "biiu4MTPFjW55qw6v5Aphtj0MjDLJ14x8ndZwkJUHIeqvaSGKeqhLY7S7Vu/S3k7/c9KwhhnaCDP9hdFNUhcNA=="
},
"Microsoft.AspNetCore.Authorization": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "9Nic17acgZbysUlhGc+TEd9F8jI01kC6+V31sC7/xI5v2OSWGL8NhdYaB/Iu4KnDRoQEolg6qvepGsVfeYpIYA==",
"dependencies": {
"Microsoft.AspNetCore.Metadata": "8.0.3",
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
"Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.AspNetCore.Components": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "q1Da8sfxG+B+BSYpc/3RKNEdzGcLbDTXkTUqekY65kXMMVCTqTAQ0Zs4csmB7FNVTFSjwaw1dGMFD0bQ+erlBw==",
"dependencies": {
"Microsoft.AspNetCore.Authorization": "8.0.3",
"Microsoft.AspNetCore.Components.Analyzers": "8.0.3"
}
},
"Microsoft.AspNetCore.Components.Analyzers": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "iERLuYM+YFI/K1jkinr1YeAkJYHUcijPiPCKgmgs2ZhJLqiIVJRT08vUtIsfhiFtGiI5MIzK0R1BZHyS3yAQng=="
},
"Microsoft.AspNetCore.Components.Forms": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "OxY5NDmePnn6FMb+Fum57YL7LCHk3u2Wg0qSln3uZSayo+oIxYuoGnqH2dUMp1P5vOPfq17NKCIIEbxfU2dirQ==",
"dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3"
}
},
"Microsoft.AspNetCore.Components.Web": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "bHWJiz/JhjptK3iYzha0Rm73chjFcbMAOD9DdDq2tn1rp4rQa/K7O/zdnZpSYAT3nI33Q0aY6ts6t0PUVu5hCA==",
"dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3",
"Microsoft.AspNetCore.Components.Forms": "8.0.3",
"Microsoft.Extensions.DependencyInjection": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0",
"Microsoft.JSInterop": "8.0.3",
"System.IO.Pipelines": "8.0.0"
}
},
"Microsoft.AspNetCore.Metadata": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "MAdmICjtSckGDutLRMydRI0pvBcGw/WoC4UC+hZ999idVW96l5iJlhyrtakgYkF5Rp0ekNVNWA+onP2gJZUkpw=="
},
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "8.0.1",
"contentHash": "fGLiCRLMYd00JYpClraLjJTNKLmMJPnqxMaiRzEBIIvevlzxz33mXy39Lkd48hu1G+N21S7QpaO5ZzKsI6FRuA=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Localization": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "EjHnIiEwNq9xl8S36hf0nj64IF3DTQ1l5PVK8Vo+QocYKDKpDPONHNJC8env0DPwod7T5oA1HYLLo2mdSTCgrQ==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1",
"Microsoft.Extensions.Localization.Abstractions": "8.0.3",
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
"Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Localization.Abstractions": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "k/kUPm1FQBxcs9/vsM1eF4qIOg2Sovqh/+KUGHur5Mc0Y3OFGuoz9ktBX7LA0gPz53SZhW3W3oaSaMFFcjgM6Q=="
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "8.0.1",
"contentHash": "RIFgaqoaINxkM2KTOw72dmilDmTrYA0ns2KW4lDz4gZ2+o6IQ894CzmdL3StM2oh7QQq44nCWiqKqc4qUI9Jmg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1"
}
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "8.0.2",
"contentHash": "dWGKvhFybsaZpGmzkGCbNNwBD1rVlWzrZKANLW/CcbFJpCEceMCGzT7zZwHOGBCbwM0SzBuceMj5HN1LKV1QqA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
},
"Microsoft.JSInterop": {
"type": "Transitive",
"resolved": "8.0.3",
"contentHash": "Oi21Fa7KubCzafwXb2IOdSGg24+/ylYGwrJgAYdWmgXBj04Oj/1b8vr9hrcoFKjQ6K18ryHYh35ZO/CCIEhuzg=="
},
"System.IO.Pipelines": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
}
},
"net8.0/osx-arm64": {}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
documentation/AI Studio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

21
documentation/Build.md Normal file
View File

@ -0,0 +1,21 @@
# Building
You just want to use the app? Then simply [download the appropriate setup for your operating system](Setup.md). This chapter is intended for developers who want to modify and customize the code.
In order to build MindWork AI Studio from source instead of using the pre-built binaries, follow these steps:
1. Install the [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0).
2. [Install the Rust compiler](https://www.rust-lang.org/tools/install) in the latest version.
3. [Install NuShell](https://www.nushell.sh/). This shell works on all operating systems and is required because the build script is written in NuShell.
4. Clone the repository.
5. Open a terminal with NuShell.
6. Navigate to the `/app/MindWork AI Studio` directory within the repository.
7. To build the current version, run `nu build.nu publish`.
- This will build the app for the current operating system, for both x64 (Intel, AMD) and ARM64 (e.g., Apple Silicon, Raspberry Pi).
- The setup program will be located in `runtime/target/release/bundle` afterward.
8. In order to create a new release:
1. To prepare a new release, run `nu build.nu prepare <ACTION>`, where `<ACTION>` is either `patch`, `minor`, or `major`. In case you need to adjust the version manually, you can do so in the `metadata.txt` file at the root of the repository; the first line contains the version number.
2. The actual release will be built by our GitHub Workflow. For this to work, you need to create a PR with your changes.
3. Before finishing the PR, make sure to create a changelog file in the `/app/MindWork AI Studio/wwwroot/changelog` directory. The file should be named `vX.Y.Z.md` and contain the changes made in the release (your changes and any other changes that are part of the release).
4. Your proposed changes will be reviewed and merged.
5. Once the PR is merged, a member of the maintainers team will create & push an appropriate git tag in the format `vX.Y.Z`.
6. The GitHub Workflow will then build the release and upload it to the [release page](https://github.com/MindWorkAI/AI-Studio/releases/latest).
7. Building the release including virus scanning takes about 2 1/2 hours.

121
documentation/Setup.md Normal file
View File

@ -0,0 +1,121 @@
# Install the app
To get started, choose your operating system where you want to install the app:
- [Windows](#windows)
- [macOS](#macos)
- [Linux](#linux)
## Windows
AI Studio is only available for modern 64-bit Windows systems. When you have an older 32-bit system, you won't be able to run the app. We require an updated Windows 10 or 11 version; the app won't properly work on Windows 7 or 8. Next, we have to figure out if you have an Intel/AMD or a modern ARM system on your Windows machine.
- **Copilot Plus PC:** Do you own one of the new Copilot Plus PCs? If so, you most likely have an ARM system. When your machine has a Qualcomm sticker on it, you have an ARM system for sure. [Download the ARM version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_arm64-setup.exe) of AI Studio.
- **Windows on macOS:** Do you run Windows using Parallels on an Apple Silicon system (M1, M2, M3, M4)? Then you have an ARM system as well. [Download the ARM version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_arm64-setup.exe) of AI Studio.
- **Intel/AMD:** In almost all other cases, you have an Intel/AMD system. [Download the x64 version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_x64-setup.exe) of AI Studio.
When you try to install the app, you get a message regarding protection of your PC (see screenshots below). For Windows to trust our app, we need to purchase a certificate that costs around $1000 per year. Would you like to help us with this? [Please consider supporting us](../Sponsors.md). You might want to [visit our release page](https://github.com/MindWorkAI/AI-Studio/releases/latest). There, we provide VirusTotal scan results for each release. If you are unsure about the safety of the app, you can check the results there. Ensure that the majority of scanners have a green checkmark.
When you are confident in the app's safety, click on "More info" and then "Run anyway" to proceed with the installation:
![Windows Protection 1](Windows%20Warning%201.png)
![Windows Protection 2](Windows%20Warning%202.png)
Once the app is installed, it will check for updates automatically. If a new version is available, you will be prompted to install it.
## macOS
AI Studio is available for modern 64-bit macOS systems. The minimum requirement is macOS 10.13 (High Sierra). Next, we have to figure out if you have an Intel or a modern Apple Silicon (ARM) system.
- **Apple Silicon:** Do you have a modern Apple Silicon system (M1, M2, M3, M4)? [Download the ARM version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_aarch64.dmg) of AI Studio.
- **Time of purchase:** Did you buy your Mac in 2021 or later? Then you probably have an ARM system. [Download the ARM version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_aarch64.dmg) of AI Studio.
- **Check System Information:** On your macOS, click on the Apple logo in the top left corner, then "About This Mac." In the window that opens, you can see the processor type. When it says "Apple M1" or similar, you have an ARM system. [Download the ARM version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_aarch64.dmg) of AI Studio.
- **Intel:** Older Macs have an Intel processor. [Download the Intel version](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/MindWork%20AI%20Studio_x64.dmg) of AI Studio.
After downloading the file, open the DMG file and drag the app to your Applications folder:
![macOS Installation 1](macOS%20Mount.png)
When you try to open the app, you get a message that the app is damaged:
![macOS Installation 2](macOS%20Damage.png)
This is because we don't have an Apple Developer account, which costs around $100 per year. Would you like to help us with this? [Please consider supporting us](../Sponsors.md). You might want to [visit our release page](https://github.com/MindWorkAI/AI-Studio/releases/latest). There, we provide VirusTotal scan results for each release. If you are unsure about the safety of the app, you can check the results there. Ensure that the majority of scanners have a green checkmark.
When you are confident in the app's safety, follow these steps:
1. Start the Terminal app. Just use Spotlight (Cmd + Space) and type "Terminal."
2. Open your Finder and navigate to the Applications folder.
3. Find the MindWork AI Studio app.
4. Type this command: `xattr -r -d com.apple.quarantine ` (with a space at the end).
5. Drag the MindWork AI Studio app from the Finder into the Terminal window. The path to the app will be added to the command automatically.
6. The final command should be: `xattr -r -d com.apple.quarantine /Applications/MindWork\ AI\ Studio.app`. Press Enter.
7. Now, you might close the Terminal app and the Finder.
The AI Studio app should now open without any issues. Once the app is installed, it will check for updates automatically. If a new version is available, you will be prompted to install it.
## Linux
AI Studio is available for modern 64-bit Linux systems. The app is provided as an AppImage and a DEB package. We test our app using Ubuntu 22.04, but it should work on other distributions as well.
1. **Choosing between the AppImage and DEB package:**
- **AppImage:** This is a single file that you can run without installation. It is a bit larger than the DEB package. Main advantage is that automatic updates are supported. When a new version is available, the app will prompt you to download and install it. Unfortunately, the AppImage version is not yet supported for ARM systems.
- **DEB package:** This is a traditional Debian package that you can install using your package manager. It is smaller than the AppImage. The main disadvantage is that you have to check for updates manually. Unfortunately, we don't have a Debian repository for automatic updates yet. That means:
- You won't get a notification when a new version is available.
- You have to download any updated DEB package from our [release page](https://github.com/MindWorkAI/AI-Studio/releases/latest) and install it manually again.
Another issue is that the DEB package is only compatible with Debian-based distributions. For other distributions, you have to use the AppImage version.
2. **Choosing CPU architecture:**
Next, we have to figure out if you have an Intel/AMD or a modern ARM system on your Linux machine. Open a terminal and run the command `uname -m`. When the output is `x86_64`, you have an Intel/AMD system. If the output is `aarch64`, you have an ARM system.
- **Intel/AMD:** [Download the AppImage](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/mind-work-ai-studio_amd64.AppImage) (recommended) or [DEB package](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/mind-work-ai-studio_amd64.deb) of AI Studio.
- **ARM:** Unfortunately, the AppImage version is not yet supported for ARM systems. [Download the DEB package](https://github.com/MindWorkAI/AI-Studio/releases/latest/download/mind-work-ai-studio_arm64.deb) of AI Studio instead.
### DEB Package Installation
**Install the app using the desktop environment:**
1. Download the DEB package from the link above.
2. Open your file manager and navigate to the Downloads folder.
3. Right-click on the DEB package and select "Open with other application":
![Linux Installation 1](Ubuntu%20DEB%20Open.png)
4. Choose your package manager, e.g., "Software Install":
![Linux Installation 2](Ubuntu%20DEB%20Install%201.png)
5. Click on "Install":
![Linux Installation 3](Ubuntu%20DEB%20Install%202.png)
6. Enter your password and click on "Authenticate."
7. Wait for the installation to finish.
8. Close the package manager.
9. You can now find the app in your application menu.
**Install the app using the terminal:**
1. Download the DEB package from the link above.
2. Open a terminal and navigate to the Downloads folder: `cd Downloads`.
3. Install the DEB package: `sudo apt install ./mind-work-ai-studio_amd64.deb`.
4. Enter your password and press Enter.
5. Wait for the installation to finish.
6. You can now find the app in your application menu.
### AppImage Installation
**Prepare the AppImage using the desktop environment:**
1. Download the AppImage from the link above.
2. Open your file manager and navigate to the Downloads folder.
3. Right-click on the AppImage and select "Properties":
![Ubuntu Installation 4](Ubuntu%20AppImage%20Properties.png)
4. Go to the "Permissions" tab and check the box "Allow executing file as program":
![Ubuntu Installation 5](Ubuntu%20AppImage%20Permissions.png)
5. Close the property window.
6. You might want to move the AppImage to a more convenient location, e.g., your home directory.
7. Double-click the AppImage to run it.
**Prepare the AppImage using the terminal:**
1. Download the AppImage from the link above.
2. Open a terminal and navigate to the Downloads folder: `cd Downloads`.
3. Make the AppImage executable: `chmod +x mind-work-ai-studio_amd64.AppImage`.
4. You might want to move the AppImage to a more convenient location, e.g., your home directory: `mv mind-work-ai-studio_amd64.AppImage ~/`.
4. Now you can run the AppImage from your file manager (double-click) or the terminal: `./mind-work-ai-studio_amd64.AppImage`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,9 +1,9 @@
0.5.0 0.5.0
2024-06-02 19:03:30 UTC 2024-06-17 10:47:38 UTC
151 153
8.0.205 (commit 3e1383b780) 8.0.206 (commit bb12410699)
8.0.5 (commit 087e15321b) 8.0.6 (commit 3b8b000a0e)
1.78.0 (commit 9b00956e5) 1.79.0 (commit 129f3b996)
6.19.1 6.20.0
1.6.1 1.6.1
0c1e2a28ab9, dev testing 4d553138be9, dev debug

357
runtime/Cargo.lock generated
View File

@ -326,6 +326,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bincode" name = "bincode"
version = "1.3.3" version = "1.3.3"
@ -1611,7 +1617,26 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http 0.2.12",
"indexmap 2.2.6",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "h2"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http 1.1.0",
"indexmap 2.2.6", "indexmap 2.2.6",
"slab", "slab",
"tokio", "tokio",
@ -1707,6 +1732,17 @@ dependencies = [
"itoa 1.0.11", "itoa 1.0.11",
] ]
[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
"itoa 1.0.11",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.6" version = "0.4.6"
@ -1714,7 +1750,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 0.2.12",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http 1.1.0",
]
[[package]]
name = "http-body-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"pin-project-lite", "pin-project-lite",
] ]
@ -1746,9 +1805,9 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2 0.3.24",
"http", "http 0.2.12",
"http-body", "http-body 0.4.6",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa 1.0.11", "itoa 1.0.11",
@ -1760,6 +1819,26 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2 0.4.5",
"http 1.1.0",
"http-body 1.0.0",
"httparse",
"itoa 1.0.11",
"pin-project-lite",
"smallvec",
"tokio",
"want",
]
[[package]] [[package]]
name = "hyper-tls" name = "hyper-tls"
version = "0.5.0" version = "0.5.0"
@ -1767,12 +1846,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [ dependencies = [
"bytes", "bytes",
"hyper", "hyper 0.14.28",
"native-tls", "native-tls",
"tokio", "tokio",
"tokio-native-tls", "tokio-native-tls",
] ]
[[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 1.3.1",
"hyper-util",
"native-tls",
"tokio",
"tokio-native-tls",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.3.1",
"pin-project-lite",
"socket2 0.5.7",
"tokio",
"tower",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.60" version = "0.1.60"
@ -2204,6 +2319,7 @@ dependencies = [
"flexi_logger", "flexi_logger",
"keyring", "keyring",
"log", "log",
"reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"tauri", "tauri",
@ -2212,6 +2328,12 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "minisign-verify"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.2" version = "0.7.2"
@ -2444,6 +2566,17 @@ dependencies = [
"objc_exception", "objc_exception",
] ]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]] [[package]]
name = "objc-sys" name = "objc-sys"
version = "0.3.3" version = "0.3.3"
@ -2580,6 +2713,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "300.3.1+3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.95" version = "0.9.95"
@ -2588,6 +2730,7 @@ checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
"openssl-src",
"pkg-config", "pkg-config",
"vcpkg", "vcpkg",
] ]
@ -2818,6 +2961,26 @@ dependencies = [
"siphasher", "siphasher",
] ]
[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.13" version = "0.2.13"
@ -3152,11 +3315,11 @@ dependencies = [
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2 0.3.24",
"http", "http 0.2.12",
"http-body", "http-body 0.4.6",
"hyper", "hyper 0.14.28",
"hyper-tls", "hyper-tls 0.5.0",
"ipnet", "ipnet",
"js-sys", "js-sys",
"log", "log",
@ -3165,7 +3328,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls-pemfile", "rustls-pemfile 1.0.4",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
@ -3183,6 +3346,72 @@ dependencies = [
"winreg 0.50.0", "winreg 0.50.0",
] ]
[[package]]
name = "reqwest"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
dependencies = [
"base64 0.22.1",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.4.5",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper-tls 0.6.0",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls-pemfile 2.1.2",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.52.0",
]
[[package]]
name = "rfd"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
dependencies = [
"block",
"dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"lazy_static",
"log",
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.37.0",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.23"
@ -3234,6 +3463,22 @@ dependencies = [
"base64 0.21.7", "base64 0.21.7",
] ]
[[package]]
name = "rustls-pemfile"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
dependencies = [
"base64 0.22.1",
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.14" version = "1.0.14"
@ -3814,6 +4059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f078117725e36d55d29fafcbb4b1e909073807ca328ae8deb8c0b3843aac0fed" checksum = "f078117725e36d55d29fafcbb4b1e909073807ca328ae8deb8c0b3843aac0fed"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.7",
"bytes", "bytes",
"cocoa", "cocoa",
"dirs-next", "dirs-next",
@ -3826,9 +4072,10 @@ dependencies = [
"glob", "glob",
"gtk", "gtk",
"heck 0.4.1", "heck 0.4.1",
"http", "http 0.2.12",
"ignore", "ignore",
"indexmap 1.9.3", "indexmap 1.9.3",
"minisign-verify",
"objc", "objc",
"once_cell", "once_cell",
"open", "open",
@ -3837,7 +4084,8 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"raw-window-handle", "raw-window-handle",
"regex", "regex",
"reqwest", "reqwest 0.11.24",
"rfd",
"semver", "semver",
"serde", "serde",
"serde_json", "serde_json",
@ -3852,12 +4100,14 @@ dependencies = [
"tauri-utils", "tauri-utils",
"tempfile", "tempfile",
"thiserror", "thiserror",
"time",
"tokio", "tokio",
"url", "url",
"uuid", "uuid",
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"windows 0.39.0", "windows 0.39.0",
"zip",
] ]
[[package]] [[package]]
@ -3940,7 +4190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2d0652aa2891ff3e9caa2401405257ea29ab8372cce01f186a5825f1bd0e76" checksum = "cf2d0652aa2891ff3e9caa2401405257ea29ab8372cce01f186a5825f1bd0e76"
dependencies = [ dependencies = [
"gtk", "gtk",
"http", "http 0.2.12",
"http-range", "http-range",
"rand 0.8.5", "rand 0.8.5",
"raw-window-handle", "raw-window-handle",
@ -4238,6 +4488,27 @@ dependencies = [
"winnow 0.6.5", "winnow 0.6.5",
] ]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tokio",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.2"
@ -4689,6 +4960,19 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
dependencies = [
"windows_aarch64_msvc 0.37.0",
"windows_i686_gnu 0.37.0",
"windows_i686_msvc 0.37.0",
"windows_x86_64_gnu 0.37.0",
"windows_x86_64_msvc 0.37.0",
]
[[package]] [[package]]
name = "windows" name = "windows"
version = "0.39.0" version = "0.39.0"
@ -4843,6 +5127,12 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.39.0" version = "0.39.0"
@ -4867,6 +5157,12 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.39.0" version = "0.39.0"
@ -4891,6 +5187,12 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.39.0" version = "0.39.0"
@ -4915,6 +5217,12 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.39.0" version = "0.39.0"
@ -4957,6 +5265,12 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.39.0" version = "0.39.0"
@ -5036,7 +5350,7 @@ dependencies = [
"glib", "glib",
"gtk", "gtk",
"html5ever", "html5ever",
"http", "http 0.2.12",
"kuchikiki", "kuchikiki",
"libc", "libc",
"log", "log",
@ -5182,6 +5496,17 @@ dependencies = [
"zvariant", "zvariant",
] ]
[[package]]
name = "zip"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"byteorder",
"crc32fast",
"crossbeam-utils",
]
[[package]] [[package]]
name = "zvariant" name = "zvariant"
version = "3.15.2" version = "3.15.2"

View File

@ -9,7 +9,7 @@ authors = ["Thorsten Sommer"]
tauri-build = { version = "1.5", features = [] } tauri-build = { version = "1.5", features = [] }
[dependencies] [dependencies]
tauri = { version = "1.6", features = [ "http-all", "shell-sidecar", "path-all", "shell-open"] } tauri = { version = "1.6", features = [ "updater", "http-all", "shell-sidecar", "path-all", "shell-open"] }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
@ -19,6 +19,10 @@ tokio = "1.37.0"
flexi_logger = "0.28" flexi_logger = "0.28"
log = "0.4" log = "0.4"
[target.'cfg(target_os = "linux")'.dependencies]
# See issue https://github.com/tauri-apps/tauri/issues/4470
reqwest = { version = "0.12", features = ["native-tls-vendored"] }
[features] [features]
# this feature is used for production builds or when `devPath` points to the filesystem # this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!! # DO NOT REMOVE!!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -77,7 +77,7 @@ fn main() {
if is_prod() { if is_prod() {
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
let (mut rx, child) = Command::new_sidecar("mindworkAIStudio") let (mut rx, child) = Command::new_sidecar("mindworkAIStudioServer")
.expect("Failed to create sidecar") .expect("Failed to create sidecar")
.args([format!("{port}").as_str()]) .args([format!("{port}").as_str()])
.spawn() .spawn()

View File

@ -17,7 +17,7 @@
"open": true, "open": true,
"scope": [ "scope": [
{ {
"name": "../app/MindWork AI Studio/bin/dist/mindworkAIStudio", "name": "../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer",
"sidecar": true, "sidecar": true,
"args": true "args": true
} }
@ -58,7 +58,7 @@
"targets": "all", "targets": "all",
"identifier": "com.github.mindwork-ai.ai-studio", "identifier": "com.github.mindwork-ai.ai-studio",
"externalBin": [ "externalBin": [
"../app/MindWork AI Studio/bin/dist/mindworkAIStudio" "../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer"
], ],
"macOS": { "macOS": {
"exceptionDomain": "localhost" "exceptionDomain": "localhost"
@ -72,7 +72,15 @@
] ]
}, },
"updater": { "updater": {
"active": false "active": true,
"endpoints": [
"https://github.com/MindWorkAI/AI-Studio/releases/latest/download/latest.json"
],
"dialog": true,
"windows": {
"installMode": "passive"
},
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM3MzE4MTM4RTNDMkM0NEQKUldSTnhNTGpPSUV4TjFkczFxRFJOZWgydzFQN1dmaFlKbXhJS1YyR1RKS1RnR09jYUpMaGsrWXYK"
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 37 KiB