diff --git a/.devcontainer/buildAppImage.sh b/.devcontainer/buildAppImage.sh new file mode 100644 index 0000000000..efb963d5ac --- /dev/null +++ b/.devcontainer/buildAppImage.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +make clean + +# To reproduce https://github.com/menloresearch/jan/pull/5463 +TAURI_TOOLKIT_PATH="${XDG_CACHE_HOME:-$HOME/.cache}/tauri" +mkdir -p "$TAURI_TOOLKIT_PATH" +wget https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage -O "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage" +chmod +x "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage" + +jq '.bundle.resources = ["resources/pre-install/**/*"] | .bundle.externalBin = ["binaries/cortex-server", "resources/bin/uv"]' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json +mv /tmp/tauri.conf.json ./src-tauri/tauri.conf.json + +make build-tauri + +cp ./src-tauri/resources/bin/bun ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/bin/bun +mkdir -p ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/engines +cp -f ./src-tauri/binaries/deps/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/ +cp -f ./src-tauri/binaries/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/ +cp -rf ./src-tauri/binaries/engines ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/ +APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep AppImage | head -1) +echo $APP_IMAGE +rm -f $APP_IMAGE +/opt/bin/appimagetool ./src-tauri/target/release/bundle/appimage/Jan.AppDir $APP_IMAGE \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index db1eed38df..f42828b318 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,4 +1,20 @@ { - "name": "jan", - "image": "node:20" + "name": "Jan", + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "20" + }, + "ghcr.io/devcontainers/features/rust:1": {}, + "ghcr.io/devcontainers-extra/features/corepack:1": {} + }, + + "postCreateCommand": "./.devcontainer/postCreateCommand.sh", + + // appimagekit requires fuse to package appimage, to use fuse in the container you need to enable it on the host + "runArgs": [ + "--device", "/dev/fuse", + "--cap-add=SYS_ADMIN", + "--security-opt", "apparmor:unconfined" + ] } diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh new file mode 100755 index 0000000000..79fb4de1c0 --- /dev/null +++ b/.devcontainer/postCreateCommand.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# install tauri prerequisites + xdg-utils for xdg-open + libfuse2 for using appimagekit + +sudo apt update +sudo apt install -yqq libwebkit2gtk-4.1-dev \ + build-essential \ + curl \ + wget \ + file \ + libxdo-dev \ + libssl-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + xdg-utils \ + libfuse2 + +sudo mkdir -p /opt/bin +sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /opt/bin/appimagetool +sudo chmod +x /opt/bin/appimagetool \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.md b/.github/ISSUE_TEMPLATE/1-bug-report.md new file mode 100644 index 0000000000..495adb3056 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug-report.md @@ -0,0 +1,24 @@ +--- +name: šŸ› Bug Report +about: If something isn't working as expected šŸ¤” +title: 'bug: ' +type: Bug +--- + +**Version:** e.g. 0.5.x-xxx + +## Describe the Bug + + + +## Steps to Reproduce +1. + +## Screenshots / Logs + + + +## Operating System +- [ ] MacOS +- [ ] Windows +- [ ] Linux diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.md b/.github/ISSUE_TEMPLATE/2-feature-request.md new file mode 100644 index 0000000000..3a6c97232d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature-request.md @@ -0,0 +1,11 @@ +--- +name: šŸš€ Feature Request +about: Suggest an idea for this project 😻! +title: 'idea: ' +--- + +## Problem Statement + + +## Feature Idea + diff --git a/.github/ISSUE_TEMPLATE/3-epic.md b/.github/ISSUE_TEMPLATE/3-epic.md new file mode 100644 index 0000000000..afffc6b5cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-epic.md @@ -0,0 +1,12 @@ +--- +name: 🌟 Epic +about: Major building block that advances Jan's goals +title: 'epic: ' +type: Epic +--- + +## Goal + +## Tasklist + +## Out of scope diff --git a/.github/ISSUE_TEMPLATE/4-goal.md b/.github/ISSUE_TEMPLATE/4-goal.md new file mode 100644 index 0000000000..28b32382aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4-goal.md @@ -0,0 +1,13 @@ +--- +name: šŸŽÆ Goal +about: External communication of Jan's roadmap and objectives +title: 'goal: ' +type: Goal +--- + +## Goal + +## Tasklist + +## Out of scope + diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index be0f343198..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "\U0001F41B Bug Report" -description: "If something isn't working as expected \U0001F914" -labels: [ "type: bug" ] -title: 'bug: [DESCRIPTION]' - -body: - - type: input - validations: - required: true - attributes: - label: "Jan version" - description: "**Tip:** The version is in the app's bottom right corner" - placeholder: "e.g. 0.5.x-xxx" - - - type: textarea - validations: - required: true - attributes: - label: "Describe the Bug" - description: "A clear & concise description of the bug" - - - type: textarea - attributes: - label: "Steps to Reproduce" - description: | - Please list out steps to reproduce the issue - placeholder: | - 1. Go to '...' - 2. Click on '...' - - - type: textarea - attributes: - label: "Screenshots / Logs" - description: | - You can find logs in: ~/jan/logs/app.logs - - - type: checkboxes - attributes: - label: "What is your OS?" - options: - - label: MacOS - - label: Windows - - label: Linux diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2d49f0d6e2..057cb81489 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,5 @@ -## To encourage contributors to use issue templates, we don't allow blank issues blank_issues_enabled: true - contact_links: - - name: "\1F4AC Jan Discussions" - url: "https://github.com/orgs/menloresearch/discussions/categories/q-a" - about: "Get help, discuss features & roadmap, and share your projects" \ No newline at end of file + - name: Jan Discussions + url: https://github.com/orgs/menloresearch/discussions/categories/q-a + about: Get help, discuss features & roadmap, and share your projects diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index b1a10e8568..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "\U0001F680 Feature Request" -description: "Suggest an idea for this project \U0001F63B!" -title: 'idea: [DESCRIPTION]' -labels: 'type: feature request' -body: - - type: textarea - validations: - required: true - attributes: - label: "Problem Statement" - description: "Describe the problem you're facing" - placeholder: | - I'm always frustrated when ... - - - type: textarea - validations: - required: true - attributes: - label: "Feature Idea" - description: "Describe what you want instead. Examples are welcome!" \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/model_request.yml b/.github/ISSUE_TEMPLATE/model_request.yml deleted file mode 100644 index 7f7c4f63c0..0000000000 --- a/.github/ISSUE_TEMPLATE/model_request.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "\U0001F929 Model Request" -description: "Request a new model to be compiled" -title: 'feat: [DESCRIPTION]' -labels: 'type: model request' -body: - - type: markdown - attributes: - value: "**Tip:** Download any HuggingFace model in app ([see guides](https://jan.ai/docs/models/manage-models#add-models)). Use this form for unsupported models only." - - type: textarea - validations: - required: true - attributes: - label: "Model Requests" - description: "If applicable, include the source URL, licenses, and any other relevant information" - - type: checkboxes - attributes: - label: "Which formats?" - options: - - label: GGUF (llama.cpp) - - label: TensorRT (TensorRT-LLM) - - label: ONNX (Onnx Runtime) diff --git a/.github/ISSUE_TEMPLATE/roadmap.md b/.github/ISSUE_TEMPLATE/roadmap.md deleted file mode 100644 index 7947f31bf9..0000000000 --- a/.github/ISSUE_TEMPLATE/roadmap.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Roadmap -about: Plan Roadmap items with subtasks -title: 'roadmap: ' -labels: 'type: planning' -assignees: '' - ---- - -## Goal - -## Tasklist - -### Frontend -- [ ] link to janhq/jan epics - -**Bugs** -- [ ] link to bugs - -### Backend -- [ ] link to janhq/cortex.cpp epics - -**Bugs** -- [ ] link to bug issues - -### Infra -- [ ] link to infra issues - -### Administrative / Management -- [ ] link to infra issues - -### Marketing - -------- -## Resources diff --git a/.github/workflows/issues.yaml b/.github/workflows/issues.yaml new file mode 100644 index 0000000000..732f668620 --- /dev/null +++ b/.github/workflows/issues.yaml @@ -0,0 +1,16 @@ +name: Adds all issues to project board + +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v1.0.2 + with: + project-url: https://github.com/orgs/${{ vars.ORG_NAME }}/projects/${{ vars.JAN_PROJECT_NUMBER }} + github-token: ${{ secrets.AUTO_ADD_TICKET_PAT }} diff --git a/.github/workflows/jan-electron-linter-and-test.yml b/.github/workflows/jan-electron-linter-and-test.yml index 6c2842c30c..e895baf065 100644 --- a/.github/workflows/jan-electron-linter-and-test.yml +++ b/.github/workflows/jan-electron-linter-and-test.yml @@ -154,6 +154,10 @@ jobs: with: node-version: 20 + - name: Install tauri-driver dependencies + run: | + cargo install tauri-driver --locked + # Clean cache, continue on error - name: 'Cleanup cache' shell: powershell @@ -192,11 +196,25 @@ jobs: with: fetch-depth: 0 + - uses: actions/cache@v4 # v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('**/yarn.lock') }} + - name: Installing node uses: actions/setup-node@v3 with: node-version: 20 + - name: Install tauri-driver dependencies + run: | + cargo install tauri-driver --locked + # Clean cache, continue on error - name: 'Cleanup cache' shell: powershell @@ -221,6 +239,20 @@ jobs: # run: | # make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Windows" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}" + - name: Install Prerequisites + shell: 'powershell' + # https://github.com/actions/runner-images/issues/9538 + # https://github.com/microsoft/playwright/pull/30009/files + # https://github.com/tauri-apps/wry/issues/1268 + # Evergreen Bootstrapper + # The Bootstrapper is a tiny installer that downloads + # the Evergreen Runtime matching device architecture + # and installs it locally. + # https://developer.microsoft.com/en-us/microsoft-edge/webview2/consumer/?form=MA13LH + run: | + Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe' + Start-Process -FilePath setup.exe -Verb RunAs -Wait + - name: Linter and test shell: powershell run: | @@ -240,6 +272,10 @@ jobs: with: node-version: 20 + - name: Install tauri-driver dependencies + run: | + cargo install tauri-driver --locked + # Clean cache, continue on error - name: 'Cleanup cache' shell: powershell @@ -272,6 +308,15 @@ jobs: with: node-version: 20 + - name: Install Tauri dependencies + run: | + sudo apt update + sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 webkit2gtk-driver + + - name: Install tauri-driver dependencies + run: | + cargo install tauri-driver --locked + - name: 'Cleanup cache' continue-on-error: true run: | @@ -368,6 +413,15 @@ jobs: with: node-version: 20 + - name: Install Tauri dependencies + run: | + sudo apt update + sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 webkit2gtk-driver + + - name: Install tauri-driver dependencies + run: | + cargo install tauri-driver --locked + - name: 'Cleanup cache' continue-on-error: true run: | diff --git a/.github/workflows/publish-npm-core.yml b/.github/workflows/publish-npm-core.yml index 403deb100f..f719ab3d40 100644 --- a/.github/workflows/publish-npm-core.yml +++ b/.github/workflows/publish-npm-core.yml @@ -6,7 +6,6 @@ on: workflow_dispatch: jobs: build-and-publish-plugins: - environment: production runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/template-electron-build-linux-x64.yml b/.github/workflows/template-electron-build-linux-x64.yml index 4dfab5c09b..cef11cb0ff 100644 --- a/.github/workflows/template-electron-build-linux-x64.yml +++ b/.github/workflows/template-electron-build-linux-x64.yml @@ -43,7 +43,6 @@ jobs: build-linux-x64: if: inputs.public_provider == 'github' || inputs.public_provider == 'none' runs-on: ubuntu-latest - environment: production permissions: contents: write steps: @@ -76,7 +75,6 @@ jobs: cp electron/icons_dev/jan-nightly-tray@2x.png electron/icons/icon-tray@2x.png cp electron/icons_dev/jan-nightly-tray.png electron/icons/icon-tray.png - - name: Installing node uses: actions/setup-node@v1 with: @@ -131,7 +129,7 @@ jobs: env: VERSION_TAG: ${{ inputs.new_version }} - - name: Build and publish app to aws s3 r2 or github artifactory + - name: Build and publish app to aws s3 r2 or github artifactory if: inputs.public_provider != 'github' run: | # check public_provider is true or not @@ -185,4 +183,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: jan-electron-linux-amd64-${{ inputs.new_version }}-AppImage - path: ./electron/dist/*.AppImage \ No newline at end of file + path: ./electron/dist/*.AppImage diff --git a/.github/workflows/template-electron-build-macos.yml b/.github/workflows/template-electron-build-macos.yml index ab9f002cba..8bcdcdf954 100644 --- a/.github/workflows/template-electron-build-macos.yml +++ b/.github/workflows/template-electron-build-macos.yml @@ -53,7 +53,6 @@ jobs: build-macos: if: inputs.public_provider == 'github' || inputs.public_provider == 'none' runs-on: macos-latest - environment: production permissions: contents: write steps: @@ -61,7 +60,7 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ inputs.ref }} - + - name: Replace Icons for Beta Build if: inputs.beta == true && inputs.nightly != true shell: bash @@ -161,7 +160,7 @@ jobs: p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }} p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }} - - name: Build and publish app to aws s3 r2 or github artifactory + - name: Build and publish app to aws s3 r2 or github artifactory if: inputs.public_provider != 'github' run: | # check public_provider is true or not @@ -231,4 +230,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: jan-electron-mac-universal-${{ inputs.new_version }} - path: ./electron/dist/*.dmg \ No newline at end of file + path: ./electron/dist/*.dmg diff --git a/.github/workflows/template-get-update-version.yml b/.github/workflows/template-get-update-version.yml index 70f5eace9b..2d992fbece 100644 --- a/.github/workflows/template-get-update-version.yml +++ b/.github/workflows/template-get-update-version.yml @@ -9,7 +9,6 @@ on: jobs: get-update-version: runs-on: ubuntu-latest - environment: production outputs: new_version: ${{ steps.version_update.outputs.new_version }} steps: diff --git a/.github/workflows/template-noti-discord-and-update-url-readme.yml b/.github/workflows/template-noti-discord-and-update-url-readme.yml index eaaee7e502..ce288f5415 100644 --- a/.github/workflows/template-noti-discord-and-update-url-readme.yml +++ b/.github/workflows/template-noti-discord-and-update-url-readme.yml @@ -26,7 +26,6 @@ on: jobs: noti-discord-and-update-url-readme: - environment: production runs-on: ubuntu-latest permissions: contents: write diff --git a/.github/workflows/template-tauri-build-linux-x64.yml b/.github/workflows/template-tauri-build-linux-x64.yml index 14cf6d6b87..303b001096 100644 --- a/.github/workflows/template-tauri-build-linux-x64.yml +++ b/.github/workflows/template-tauri-build-linux-x64.yml @@ -55,7 +55,6 @@ jobs: DEB_SIG: ${{ steps.packageinfo.outputs.DEB_SIG }} APPIMAGE_SIG: ${{ steps.packageinfo.outputs.APPIMAGE_SIG }} APPIMAGE_FILE_NAME: ${{ steps.packageinfo.outputs.APPIMAGE_FILE_NAME }} - environment: production permissions: contents: write steps: @@ -96,7 +95,7 @@ jobs: run: | cargo install ctoml - - name: Install Tauri dependecies + - name: Install Tauri dependencies run: | sudo apt update sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 diff --git a/.github/workflows/template-tauri-build-macos.yml b/.github/workflows/template-tauri-build-macos.yml index 086e14ad28..038a084fa3 100644 --- a/.github/workflows/template-tauri-build-macos.yml +++ b/.github/workflows/template-tauri-build-macos.yml @@ -63,7 +63,6 @@ jobs: outputs: MAC_UNIVERSAL_SIG: ${{ steps.metadata.outputs.MAC_UNIVERSAL_SIG }} TAR_NAME: ${{ steps.metadata.outputs.TAR_NAME }} - environment: production permissions: contents: write steps: diff --git a/.vscode/settings.json b/.vscode/settings.json index 9bf4d12b52..78bf4f0ab7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true + "editor.formatOnSave": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer" + } } diff --git a/Makefile b/Makefile index 56b50a9d27..6e69c602dd 100644 --- a/Makefile +++ b/Makefile @@ -33,23 +33,14 @@ dev: install-and-build yarn copy:lib yarn dev -# Deprecated soon -dev-tauri: install-and-build - yarn install:cortex - yarn download:bin - yarn copy:lib - yarn dev:tauri - # Linting lint: install-and-build yarn lint # Testing test: lint - # yarn build:test - # yarn test:coverage - # Need e2e setup for tauri backend yarn test + yarn test:e2e # Builds and publishes the app build-and-publish: install-and-build diff --git a/core/package.json b/core/package.json index 1e62913753..22c815e5b3 100644 --- a/core/package.json +++ b/core/package.json @@ -23,24 +23,24 @@ }, "devDependencies": { "@npmcli/arborist": "^7.1.0", - "@types/jest": "^29.5.14", + "@types/jest": "^30.0.0", "@types/node": "^22.10.0", "@types/pacote": "^11.1.7", "@types/request": "^2.48.12", "electron": "33.2.1", "eslint": "8.57.0", "eslint-plugin-jest": "^27.9.0", - "jest": "^29.7.0", + "jest": "^30.0.3", "jest-junit": "^16.0.0", "jest-runner": "^29.7.0", "pacote": "^21.0.0", "request": "^2.88.2", "request-progress": "^3.0.0", - "rimraf": "^3.0.2", + "rimraf": "^6.0.1", "rolldown": "1.0.0-beta.1", "ts-jest": "^29.2.5", "tslib": "^2.6.2", - "typescript": "^5.3.3" + "typescript": "^5.8.3" }, "dependencies": { "rxjs": "^7.8.1", diff --git a/core/src/browser/models/utils.test.ts b/core/src/browser/models/utils.test.ts index 313ad09692..2a1a09d23b 100644 --- a/core/src/browser/models/utils.test.ts +++ b/core/src/browser/models/utils.test.ts @@ -29,7 +29,7 @@ describe('validationRules', () => { expect(validationRules.top_k(1)).toBe(true) expect(validationRules.top_k(0)).toBe(true) expect(validationRules.top_k(-0.1)).toBe(false) - expect(validationRules.top_k(1.1)).toBe(false) + expect(validationRules.top_k(1.1)).toBe(true) expect(validationRules.top_k('0.5')).toBe(false) }) @@ -68,8 +68,8 @@ describe('validationRules', () => { expect(validationRules.frequency_penalty(0.5)).toBe(true) expect(validationRules.frequency_penalty(1)).toBe(true) expect(validationRules.frequency_penalty(0)).toBe(true) - expect(validationRules.frequency_penalty(-0.1)).toBe(false) - expect(validationRules.frequency_penalty(1.1)).toBe(false) + expect(validationRules.frequency_penalty(-0.1)).toBe(true) + expect(validationRules.frequency_penalty(1.1)).toBe(true) expect(validationRules.frequency_penalty('0.5')).toBe(false) }) @@ -77,8 +77,8 @@ describe('validationRules', () => { expect(validationRules.presence_penalty(0.5)).toBe(true) expect(validationRules.presence_penalty(1)).toBe(true) expect(validationRules.presence_penalty(0)).toBe(true) - expect(validationRules.presence_penalty(-0.1)).toBe(false) - expect(validationRules.presence_penalty(1.1)).toBe(false) + expect(validationRules.presence_penalty(-0.1)).toBe(true) + expect(validationRules.presence_penalty(1.1)).toBe(true) expect(validationRules.presence_penalty('0.5')).toBe(false) }) @@ -255,7 +255,7 @@ describe('extractInferenceParams', () => { top_p: 0.9, stream: true, max_tokens: 50.3, - invalid_param: 'should_be_ignored' + invalid_param: 'should_be_ignored', } const result = extractInferenceParams(modelParams as any) @@ -264,7 +264,7 @@ describe('extractInferenceParams', () => { token_limit: 100, top_p: 0.9, stream: true, - max_tokens: 50 + max_tokens: 50, }) }) @@ -296,9 +296,9 @@ describe('extractModelLoadParams', () => { prompt_template: 'template', llama_model_path: '/path/to/model', vision_model: false, - invalid_param: 'should_be_ignored' + invalid_param: 'should_be_ignored', } - + const result = extractModelLoadParams(modelParams as any) expect(result).toEqual({ ctx_len: 2048, @@ -308,23 +308,23 @@ describe('extractModelLoadParams', () => { cpu_threads: 8, prompt_template: 'template', llama_model_path: '/path/to/model', - vision_model: false + vision_model: false, }) }) it('should handle parameters without validation rules', () => { - const modelParams = { + const modelParams = { engine: 'llama', pre_prompt: 'System:', system_prompt: 'You are helpful', - model_path: '/path' + model_path: '/path', } const result = extractModelLoadParams(modelParams as any) expect(result).toEqual({ engine: 'llama', pre_prompt: 'System:', system_prompt: 'You are helpful', - model_path: '/path' + model_path: '/path', }) }) diff --git a/core/src/browser/models/utils.ts b/core/src/browser/models/utils.ts index d3fe0cb017..c11bed4c7f 100644 --- a/core/src/browser/models/utils.ts +++ b/core/src/browser/models/utils.ts @@ -8,13 +8,13 @@ import { ModelParams, ModelRuntimeParams, ModelSettingParams } from '../../types export const validationRules: { [key: string]: (value: any) => boolean } = { temperature: (value: any) => typeof value === 'number' && value >= 0 && value <= 2, token_limit: (value: any) => Number.isInteger(value) && value >= 0, - top_k: (value: any) => typeof value === 'number' && value >= 0 && value <= 1, + top_k: (value: any) => typeof value === 'number' && value >= 0, top_p: (value: any) => typeof value === 'number' && value >= 0 && value <= 1, stream: (value: any) => typeof value === 'boolean', max_tokens: (value: any) => Number.isInteger(value) && value >= 0, stop: (value: any) => Array.isArray(value) && value.every((v) => typeof v === 'string'), - frequency_penalty: (value: any) => typeof value === 'number' && value >= 0 && value <= 1, - presence_penalty: (value: any) => typeof value === 'number' && value >= 0 && value <= 1, + frequency_penalty: (value: any) => typeof value === 'number' && value >= -2 && value <= 2, + presence_penalty: (value: any) => typeof value === 'number' && value >= -2 && value <= 2, repeat_last_n: (value: any) => typeof value === 'number', repeat_penalty: (value: any) => typeof value === 'number', min_p: (value: any) => typeof value === 'number', @@ -50,6 +50,22 @@ export const normalizeValue = (key: string, value: any) => { // Convert to integer return Math.floor(Number(value)) } + if ( + key === 'temperature' || + key === 'top_k' || + key === 'top_p' || + key === 'min_p' || + key === 'repeat_penalty' || + key === 'frequency_penalty' || + key === 'presence_penalty' || + key === 'repeat_last_n' + ) { + // Convert to float + const newValue = parseFloat(value) + if (newValue !== null && !isNaN(newValue)) { + return newValue + } + } return value } diff --git a/docs/package.json b/docs/package.json index fd691a09ac..08ff495c0d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -27,7 +27,7 @@ "embla-carousel-react": "^8.0.0", "fs": "^0.0.1-security", "gray-matter": "^4.0.3", - "lucide-react": "^0.372.0", + "lucide-react": "^0.522.0", "next": "^14.1.4", "next-seo": "^6.5.0", "next-sitemap": "^4.2.3", diff --git a/docs/src/pages/docs/_assets/llama.cpp-01-updated.png b/docs/src/pages/docs/_assets/llama.cpp-01-updated.png new file mode 100644 index 0000000000..177c26145e Binary files /dev/null and b/docs/src/pages/docs/_assets/llama.cpp-01-updated.png differ diff --git a/docs/src/pages/docs/data-folder.mdx b/docs/src/pages/docs/data-folder.mdx index acbbb025b3..4c582c8012 100644 --- a/docs/src/pages/docs/data-folder.mdx +++ b/docs/src/pages/docs/data-folder.mdx @@ -56,36 +56,37 @@ cd ~/.config/Jan/data # Default install Root directory: `~/jan` + ```sh -/assistants - /jan +/assistants/ + /jan/ assistant.json -/extensions +/engines/ + /llama.cpp/ +/extensions/ extensions.json - /@janhq - /extension_A - package.json -/logs - /app.txt -/models - /model_A - model.yaml - model_A.yaml -/settings - settings.json - /@janhq - /extension_A_Settings - settings.json -/themes - /dark-dimmed - /joi-dark - /joi-light - /night-blue -/threads - /jan_thread_A - messages.jsonl - thread.json - messages.jsonl +/@janhq/ + /assistant-extension/ + /conversational-extension/ + /download-extension/ + /engine-management-extension/ + /hardware-management-extension/ + /inference-cortex-extension/ + /model-extension/ +/files/ +/logs/ + app.log +/models/ + /huggingface.co/ + /Model_Provider_A/ + /Model_A + model_A.gguf + model_A.yaml +/threads/ + /thread_A/ + messages.jsonl + thread.json + ``` ### `assistants/` @@ -93,14 +94,28 @@ Where AI personalities live. The default one (`/assistants/jan/`): ```json { - "avatar": "", + "avatar": "šŸ‘‹", "id": "jan", "object": "assistant", - "created_at": 1715132389207, + "created_at": 1750945742.536, "name": "Jan", - "description": "A default assistant that can use all downloaded models", + "description": "Jan is a helpful AI assistant that can use tools and help complete tasks for its users.", "model": "*", - "instructions": "" + "instructions": "You have access to a set of tools to help you answer the user’s question. You can use only one tool per message, and you’ll receive the result of that tool in the user’s next response. To complete a task, use tools step by step—each step should be guided by the outcome of the previous one.\nTool Usage Rules:\n1. Always provide the correct values as arguments when using tools. Do not pass variable names—use actual values instead.\n2. You may perform multiple tool steps to complete a task.\n3. Avoid repeating a tool call with exactly the same parameters to prevent infinite loops.", + "tools": [ + { + "type": "retrieval", + "enabled": false, + "useTimeWeightedRetriever": false, + "settings": { + "top_k": 2, + "chunk_size": 1024, + "chunk_overlap": 64, + "retrieval_template": "Use the following pieces of context to answer the question at the end.\n----------------\nCONTEXT: {CONTEXT}\n----------------\nQUESTION: {QUESTION}\n----------------\nHelpful Answer:" + } + } + ], + "file_ids": [] } ``` @@ -140,88 +155,65 @@ Debugging headquarters (`/logs/app.txt`): The silicon brain collection. Each model has its own `model.json`. -Full parameters: [here](/docs/models/model-parameters) +Full parameters: [here](/docs/model-parameters) -### `settings/` -Control panel. Extension settings in `/settings/@janhq/`: - -| Parameter | Description | -|----------------|----------------------------------------------------| -| key | Setting identifier | -| title | Display name | -| description | Setting explanation | -| controllerType | UI component type | -| controllerProps| Component properties | -| extensionName | Parent extension link | - -GPU settings (`settings.json`): - -| Parameter | Description | -|----------------------|--------------------------------------------| -| notify | Notification status | -| run_mode | Operating mode | -| nvidia_driver.exist | NVIDIA driver presence | -| nvidia_driver.version| Driver version | -| cuda.exist | CUDA availability | -| cuda.version | CUDA version | -| gpus[0].id | GPU identifier | -| gpus[0].vram | GPU memory (MB) | -| gpus[0].name | GPU model | -| gpus[0].arch | GPU architecture | -| gpu_highest_vram | Most capable GPU | -| gpus_in_use | Active GPUs | -| is_initial | First run flag | -| vulkan | Vulkan support | - -### `themes/` -Visual wardrobe. Each theme's `theme.json`: - -| Parameter | Description | -|------------------|-------------------------------------------| -| id | Theme identifier | -| displayName | UI name | -| reduceTransparent| Transparency control | -| nativeTheme | OS theme sync | -| variables | Component settings | - ### `threads/` Chat archive. Each thread (`/threads/jan_unixstamp/`) contains: - `messages.jsonl`: ```json - { - "id":"01J6Y6FH8PFTHQB5PNJTHEN27C", - "thread_id":"jan_1725437954", - "type":"Thread", - "role":"assistant", - "content": - [ - { - "type": "text", - "text": { - "value": "Hello! Is there something I can help you with or would you like to chat?", - "annotations": [] - } - } - ], - "status": "ready", - "created": 1725442802966, - "updated": 1725442802966, - "object": "thread.message" - } + { + "completed_at": 0, + "content": [ + { + "text": { + "annotations": [], + "value": "Hello! I can help you with various tasks. I can search for information on the internet, including news, videos, images, shopping, and more. I can also scrape webpages to extract specific information. Let me know what you need!" + }, + "type": "text" + } + ], + "created_at": 1751012639307, + "id": "01JYR7S0JB5ZBGMJV52KWMW5VW", + "metadata": { + "assistant": { + "avatar": "šŸ‘‹", + "id": "jan", + "instructions": "You have access to a set of tools to help you answer the user's question. You can use only one tool per message, and you'll receive the result of that tool in the user's next response. To complete a task, use tools step by step—each step should be guided by the outcome of the previous one.\nTool Usage Rules:\n1. Always provide the correct values as arguments when using tools. Do not pass variable names—use actual values instead.\n2. You may perform multiple tool steps to complete a task.\n3. Avoid repeating a tool call with exactly the same parameters to prevent infinite loops.", + "name": "Jan", + "parameters": "" + }, + "tokenSpeed": { + "lastTimestamp": 1751012637097, + "message": "01JYR7S0GW5M9PSHMRE7T8VQJM", + "tokenCount": 49, + "tokenSpeed": 22.653721682847895 + } + }, + "object": "thread.message", + "role": "assistant", + "status": "ready", + "thread_id": "8f2c9922-db49-4d1e-8620-279c05baf2d0", + "type": "text" + } ``` - `thread.json`: | Parameter | Description | |------------|------------------------------------------------| +| assistants | Assistant configuration clone | +| created | Creation timestamp | | id | Thread identifier | +| metadata | Additional thread data | +| model | Active model settings | | object | OpenAI compatibility marker | | title | Thread name | -| assistants | Assistant configuration clone | -| model | Active model settings | -| metadata | Additional thread data | +| updated | Updated timestamp | + + + ## Delete Jan Data Uninstall guides: [Mac](/docs/desktop/mac#step-2-clean-up-data-optional), diff --git a/docs/src/pages/docs/llama-cpp.mdx b/docs/src/pages/docs/llama-cpp.mdx index 2b4d767382..b76c42ea3d 100644 --- a/docs/src/pages/docs/llama-cpp.mdx +++ b/docs/src/pages/docs/llama-cpp.mdx @@ -33,7 +33,7 @@ import { Settings, EllipsisVertical, Plus, FolderOpen, Pencil } from 'lucide-rea Jan uses **llama.cpp** for running local AI models. You can find its settings in **Settings** () > **Local Engine** > **llama.cpp**:
-![llama.cpp](./_assets/llama.cpp-01.png) +![llama.cpp](./_assets/llama.cpp-01-updated.png)
These settings are for advanced users, you would want to check these settings when: @@ -151,6 +151,7 @@ For detailed hardware compatibility, please visit our guide for [Mac](/docs/desk | **Caching** | - Enable to store recent prompts and responses

- Improves response time for repeated prompts | Enabled | | **KV Cache Type** | - KV cache implementation type; controls memory usage and precision trade-off

- Options:

• f16 (most stable)

• q8_0 (balanced)

• q4_0 (lowest memory) | f16 | | **mmap** | - Enables memory-mapped model loading

- Reduces memory usage

- Recommended for large models | Enabled | +| **Context Shift** | - Automatically shifts the context window when the model is unable to process the entire prompt
- Ensures that the most relevant information is always included
- Recommended for long conversations and multiple tool calls | Disabled | ## Best Practices diff --git a/docs/src/pages/docs/model-parameters.mdx b/docs/src/pages/docs/model-parameters.mdx index 86846a8eae..56286bcf46 100644 --- a/docs/src/pages/docs/model-parameters.mdx +++ b/docs/src/pages/docs/model-parameters.mdx @@ -38,8 +38,6 @@ These settings are available in the model settings modal: | **Repeat Last N** | Number of tokens to consider for repeat penalty. | | **Repeat Penalty** | Penalize repeating token sequences. | | **Presence Penalty**| Penalize alpha presence (encourages new topics). | -| **Max Tokens** | Maximum length of the model's response. | -| **Stop Sequences** | Tokens or phrases that will end the model's response. | | **Frequency Penalty** | Reduces word repetition. |
diff --git a/docs/src/pages/docs/server-examples/continue-dev.mdx b/docs/src/pages/docs/server-examples/continue-dev.mdx index c6b9d50a88..a982697baa 100644 --- a/docs/src/pages/docs/server-examples/continue-dev.mdx +++ b/docs/src/pages/docs/server-examples/continue-dev.mdx @@ -36,11 +36,15 @@ Follow this [guide](https://continue.dev/docs/quickstart) to install the Continu To set up Continue for use with Jan's Local Server, you must activate the Jan API Server with your chosen model. -1. Press the `<>` button. Jan will take you to the **Local API Server** section. +1. Press the `āš™ļø Settings` button. -2. Setup the server, which includes the **IP Port**, **Cross-Origin-Resource-Sharing (CORS)** and **Verbose Server Logs**. +2. Locate `Local API Server`. -3. Press the **Start Server** button +3. Setup the server, which includes the **IP Port**, **Cross-Origin-Resource-Sharing (CORS)** and **Verbose Server Logs**. + +4. Include your user-defined API Key. + +5. Press the **Start Server** button ### Step 3: Configure Continue to Use Jan's Local Server @@ -64,30 +68,35 @@ To set up Continue for use with Jan's Local Server, you must activate the Jan AP -```json title="~/.continue/config.json" -{ - "models": [ - { - "title": "Jan", - "provider": "openai", - "model": "mistral-ins-7b-q4", - "apiKey": "EMPTY", - "apiBase": "http://localhost:1337/v1" - } - ] -} +```yaml title="~/.continue/config.yaml" +name: Local Assistant +version: 1.0.0 +schema: v1 +models: + - name: Jan + provider: openai + model: #MODEL_NAME (e.g. qwen3:0.6b) + apiKey: #YOUR_USER_DEFINED_API_KEY_HERE (e.g. hello) + apiBase: http://localhost:1337/v1 +context: + - provider: code + - provider: docs + - provider: diff + - provider: terminal + - provider: problems + - provider: folder + - provider: codebase ``` 2. Ensure the file has the following configurations: - Ensure `openai` is selected as the `provider`. - Match the `model` with the one enabled in the Jan API Server. - - Set `apiBase` to `http://localhost:1337`. - - Leave the `apiKey` field to `EMPTY`. + - Set `apiBase` to `http://localhost:1337/v1`. ### Step 4: Ensure the Using Model Is Activated in Jan -1. Navigate to `Settings` > `My Models`. -2. Click the **three dots (ā‹®)** button. +1. Navigate to `Settings` > `Model Providers`. +2. Under Llama.cpp, find the model that you would want to use. 3. Select the **Start Model** button to activate the model. diff --git a/docs/yarn.lock b/docs/yarn.lock index dd88120aa4..eb57429c80 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -5503,10 +5503,10 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" -lucide-react@^0.372.0: - version "0.372.0" - resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.372.0.tgz" - integrity sha512-0cKdqmilHXWUwWAWnf6CrrjHD8YaqPMtLrmEHXolZusNTr9epULCsiJwIOHk2q1yFxdEwd96D4zShlAj67UJdA== +lucide-react@^0.522.0: + version "0.522.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.522.0.tgz#c0951dd32936b6a7bcc474a829a251fede0bdfbd" + integrity sha512-jnJbw974yZ7rQHHEFKJOlWAefG3ATSCZHANZxIdx8Rk/16siuwjgA4fBULpXEAWx/RlTs3FzmKW/udWUuO0aRw== lz-string@^1.5.0: version "1.5.0" diff --git a/extensions/assistant-extension/package.json b/extensions/assistant-extension/package.json index 4761aa9003..f17d425885 100644 --- a/extensions/assistant-extension/package.json +++ b/extensions/assistant-extension/package.json @@ -13,7 +13,7 @@ }, "devDependencies": { "cpx": "^1.5.0", - "rimraf": "^3.0.2", + "rimraf": "^6.0.1", "rolldown": "1.0.0-beta.1", "run-script-os": "^1.1.6", "typescript": "^5.3.3" diff --git a/extensions/conversational-extension/package.json b/extensions/conversational-extension/package.json index abb76e4d0b..26ba21b9d4 100644 --- a/extensions/conversational-extension/package.json +++ b/extensions/conversational-extension/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "cpx": "^1.5.0", - "rimraf": "^3.0.2", + "rimraf": "^6.0.1", "rolldown": "1.0.0-beta.1", "ts-loader": "^9.5.0", "typescript": "^5.7.2" diff --git a/extensions/download-extension/package.json b/extensions/download-extension/package.json index 1c3f2f1749..f15f12bdb0 100644 --- a/extensions/download-extension/package.json +++ b/extensions/download-extension/package.json @@ -13,7 +13,7 @@ }, "devDependencies": { "cpx": "^1.5.0", - "rimraf": "^3.0.2", + "rimraf": "^6.0.1", "rolldown": "1.0.0-beta.1", "run-script-os": "^1.1.6", "typescript": "5.8.3", diff --git a/mise.toml b/mise.toml index ea6d3e65b4..9f6cee5c7e 100644 --- a/mise.toml +++ b/mise.toml @@ -24,13 +24,7 @@ run = [ [tasks.install] description = "Install dependencies" depends = ["config-yarn"] -run = ''' -#!/usr/bin/env bash -# Skip install on Windows per Makefile logic -if [[ "$OSTYPE" != "msys" && "$OSTYPE" != "win32" ]]; then - yarn install -fi -''' +run = "yarn install" sources = ['package.json', 'yarn.lock'] outputs = ['node_modules'] diff --git a/package.json b/package.json index 4d9f8382ed..7be0e769db 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "workspaces": { "packages": [ "core", - "web-app" + "web-app", + "tests-e2e-js" ] }, "scripts": { @@ -13,6 +14,11 @@ "build": "yarn build:web && yarn build:tauri", "test": "yarn workspace @janhq/web-app test", "test:coverage": "yarn workspace @janhq/web-app test", + "test:prepare": "yarn build:icon && yarn copy:lib && yarn copy:assets:tauri && yarn build --no-bundle ", + "test:e2e:linux": "yarn test:prepare && xvfb-run yarn workspace tests-e2-js test", + "test:e2e:win32": "yarn test:prepare && yarn workspace tests-e2-js test", + "test:e2e:darwin": "echo 'E2E tests are not supported on macOS yet due to WebDriver limitations'", + "test:e2e": "run-script-os", "dev:web": "yarn workspace @janhq/web-app dev", "dev:tauri": "CLEAN=true yarn build:icon && yarn copy:assets:tauri && tauri dev", "install:cortex:linux:darwin": "cd src-tauri/binaries && ./download.sh", @@ -39,7 +45,7 @@ "cpx": "^1.5.0", "cross-env": "^7.0.3", "husky": "^9.1.5", - "jest": "^29.7.0", + "jest": "^30.0.3", "jest-environment-jsdom": "^29.7.0", "rimraf": "^3.0.2", "run-script-os": "^1.1.6", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c55c8ea4e8..7068ffba65 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -19,8 +19,8 @@ tauri-build = { version = "2.0.2", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } log = "0.4" -tauri = { version = "2.4.0", features = [ "protocol-asset", "macos-private-api", - "test", +tauri = { version = "2.5.0", features = [ "protocol-asset", "macos-private-api", + "test" ] } tauri-plugin-log = "2.0.0-rc" tauri-plugin-shell = "2.2.0" diff --git a/src-tauri/src/core/setup.rs b/src-tauri/src/core/setup.rs index 8d8a3d557a..42ee0faa58 100644 --- a/src-tauri/src/core/setup.rs +++ b/src-tauri/src/core/setup.rs @@ -277,7 +277,12 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { ]); #[cfg(target_os = "windows")] { - let resource_dir = app_handle_for_spawn.path().resource_dir().unwrap(); + let mut resource_dir = app_handle_for_spawn.path().resource_dir().unwrap(); + // If debug + #[cfg(debug_assertions)] + { + resource_dir = resource_dir.join("binaries"); + } let normalized_path = resource_dir.to_string_lossy().replace(r"\\?\", ""); let normalized_pathbuf = PathBuf::from(normalized_path); cmd = cmd.current_dir(normalized_pathbuf); @@ -286,12 +291,12 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { #[cfg(not(target_os = "windows"))] { cmd = cmd.env("LD_LIBRARY_PATH", { - let current_app_data_dir = app_handle_for_spawn - .path() - .resource_dir() - .unwrap() - .join("binaries"); - let dest = current_app_data_dir.to_str().unwrap(); + let mut resource_dir = app_handle_for_spawn.path().resource_dir().unwrap(); + #[cfg(not(debug_assertions))] + { + resource_dir = resource_dir.join("binaries"); + } + let dest = resource_dir.to_str().unwrap(); let ld_path_env = std::env::var("LD_LIBRARY_PATH").unwrap_or_default(); format!("{}{}{}", ld_path_env, ":", dest) }); diff --git a/src-tauri/tauri.bundle.windows.nsis.template b/src-tauri/tauri.bundle.windows.nsis.template index 2da569bacc..e991d62f74 100644 --- a/src-tauri/tauri.bundle.windows.nsis.template +++ b/src-tauri/tauri.bundle.windows.nsis.template @@ -33,7 +33,7 @@ ${StrLoc} !define VERSION "jan_version" !define VERSIONWITHBUILD "jan_build" !define HOMEPAGE "" -!define INSTALLMODE "currentUser" +!define INSTALLMODE "both" !define LICENSE "" !define INSTALLERICON "D:\a\jan\jan\src-tauri\icons\icon.ico" !define SIDEBARIMAGE "" diff --git a/tests-e2e-js/.gitignore b/tests-e2e-js/.gitignore new file mode 100644 index 0000000000..1521c8b765 --- /dev/null +++ b/tests-e2e-js/.gitignore @@ -0,0 +1 @@ +dist diff --git a/tests-e2e-js/package.json b/tests-e2e-js/package.json new file mode 100644 index 0000000000..e7dc18587f --- /dev/null +++ b/tests-e2e-js/package.json @@ -0,0 +1,23 @@ +{ + "name": "tests-e2-js", + "version": "0.0.0", + "private": true, + "type": "module", + "main": "src/main.ts", + "scripts": { + "build": "tsc", + "test": "node --test --test-force-exit --loader ts-node/esm ./src/main.ts" + }, + "dependencies": { + "@tauri-e2e/selenium": "0.2.2", + "log4js": "^6.9.1", + "selenium-webdriver": "^4.22.0", + "ts-node": "^10.9.2" + }, + "devDependencies": { + "@types/node": "^20.14.9", + "@types/selenium-webdriver": "^4.1.28", + "tsimp": "^2.0.11", + "typescript": "^5.5.2" + } +} diff --git a/tests-e2e-js/src/main.ts b/tests-e2e-js/src/main.ts new file mode 100644 index 0000000000..c6e0aeba6d --- /dev/null +++ b/tests-e2e-js/src/main.ts @@ -0,0 +1,51 @@ +import assert from 'node:assert' +import { ChildProcess } from 'node:child_process' +import { afterEach, beforeEach, describe, test } from 'node:test' +import { By, until, WebDriver } from 'selenium-webdriver' +import * as e2e from '@tauri-e2e/selenium' +import { default as log4js } from 'log4js' + +let logger = log4js.getLogger() +logger.level = 'debug' + +process.env.TAURI_WEBDRIVER_LOGLEVEL = 'debug' +process.env.TAURI_WEBDRIVER_BINARY = await e2e.install.PlatformDriver() +process.env.TAURI_SELENIUM_BINARY = '../src-tauri/target/release/Jan.exe' +process.env.SELENIUM_REMOTE_URL = 'http://127.0.0.1:6655' + +//@ts-ignore fuck you javascript +e2e.setLogger(logger) + +describe('Tauri E2E tests', async () => { + let driver: WebDriver + let webDriver: ChildProcess + + beforeEach(async () => { + // Spawn WebDriver process. + webDriver = await e2e.launch.spawnWebDriver() + // wait 1 second + await new Promise((r) => setTimeout(r, 1000)) + // Create driver session. + driver = new e2e.selenium.Builder().build() + // Wait for the body element to be present + // await driver.wait(until.elementLocated({ css: 'body' })) + }) + + afterEach(async () => { + await e2e.selenium.cleanupSession(driver) + e2e.launch.killWebDriver(webDriver) + }) + + test('Find hub', async () => { + const hub = until.elementLocated(By.css('[data-test-id="menu-common:hub"')) + // console.log('GG', hub) + // @ts-ignore + await driver.wait(hub.fn, 120000) + + const menuElement = await driver.findElement({ + css: '[data-test-id="menu-common:hub"]', + }) + assert(menuElement !== null, 'Hub menu element should be available') + await menuElement.isDisplayed() + }) +}) diff --git a/tests-e2e-js/tsconfig.json b/tests-e2e-js/tsconfig.json new file mode 100644 index 0000000000..6189f7d389 --- /dev/null +++ b/tests-e2e-js/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "src/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ], +} diff --git a/web-app/package.json b/web-app/package.json index 1719665602..b56f09a0d5 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -46,7 +46,7 @@ "i18next": "^25.0.1", "katex": "^0.16.22", "lodash.debounce": "^4.0.8", - "lucide-react": "^0.503.0", + "lucide-react": "^0.522.0", "motion": "^12.10.5", "next-themes": "^0.4.6", "posthog-js": "^1.246.0", @@ -56,6 +56,7 @@ "react-i18next": "^15.5.1", "react-joyride": "^2.9.3", "react-markdown": "^10.1.0", + "react-resizable-panels": "^3.0.3", "react-syntax-highlighter": "^15.6.1", "react-syntax-highlighter-virtualized-renderer": "^1.1.0", "react-textarea-autosize": "^8.5.9", @@ -88,7 +89,7 @@ "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", "tailwind-merge": "^3.2.0", - "typescript": "~5.7.2", + "typescript": "~5.8.3", "typescript-eslint": "^8.26.1", "vite": "^6.3.0", "vite-plugin-node-polyfills": "^0.23.0", diff --git a/web-app/src/components/ui/resizable.tsx b/web-app/src/components/ui/resizable.tsx new file mode 100644 index 0000000000..a3d586cf17 --- /dev/null +++ b/web-app/src/components/ui/resizable.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import { GripVerticalIcon } from 'lucide-react' +import * as ResizablePrimitive from 'react-resizable-panels' + +import { cn } from '@/lib/utils' + +function ResizablePanelGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ResizablePanel({ + ...props +}: React.ComponentProps) { + return +} + +function ResizableHandle({ + withHandle, + className, + ...props +}: React.ComponentProps & { + withHandle?: boolean +}) { + return ( + div]:rotate-90', + className + )} + {...props} + > + {withHandle && ( +
+ +
+ )} +
+ ) +} + +export { ResizablePanelGroup, ResizablePanel, ResizableHandle } diff --git a/web-app/src/constants/routes.ts b/web-app/src/constants/routes.ts index db741e9e6a..e9997590a4 100644 --- a/web-app/src/constants/routes.ts +++ b/web-app/src/constants/routes.ts @@ -5,6 +5,7 @@ export const route = { assistant: '/assistant', settings: { index: '/settings', + model_providers: '/settings/providers', providers: '/settings/providers/$providerName', general: '/settings/general', appearance: '/settings/appearance', diff --git a/web-app/src/containers/Card.tsx b/web-app/src/containers/Card.tsx index 324b98b2d2..7d68550dbb 100644 --- a/web-app/src/containers/Card.tsx +++ b/web-app/src/containers/Card.tsx @@ -10,43 +10,63 @@ type CardProps = { type CardItemProps = { title?: string | ReactNode description?: string | ReactNode + descriptionOutside?: string | ReactNode align?: 'start' | 'center' | 'end' actions?: ReactNode column?: boolean className?: string + classNameWrapperAction?: string } export function CardItem({ title, description, + descriptionOutside, className, + classNameWrapperAction, align = 'center', column, actions, }: CardItemProps) { return ( -
-
-

{title}

- {description && ( - - {description} - + <> +
+
+

{title}

+ {description && ( + + {description} + + )} +
+ {actions && ( +
+ {actions} +
)}
- {actions && ( -
{actions}
+ {descriptionOutside && ( + + {descriptionOutside} + )} -
+ ) } diff --git a/web-app/src/containers/ChatInput.tsx b/web-app/src/containers/ChatInput.tsx index 2d16b2eee7..0cecb2bf3f 100644 --- a/web-app/src/containers/ChatInput.tsx +++ b/web-app/src/containers/ChatInput.tsx @@ -365,6 +365,7 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => { rows={1} maxRows={10} value={prompt} + data-test-id={'chat-input'} onChange={(e) => { setPrompt(e.target.value) // Count the number of newlines to estimate rows @@ -567,6 +568,7 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => { variant={!prompt.trim() ? null : 'default'} size="icon" disabled={!prompt.trim()} + data-test-id="send-message-button" onClick={() => handleSendMesage(prompt)} > {streamingContent ? ( diff --git a/web-app/src/containers/ChatWidthSwitcher.tsx b/web-app/src/containers/ChatWidthSwitcher.tsx index 27cc3c69d4..10417200e8 100644 --- a/web-app/src/containers/ChatWidthSwitcher.tsx +++ b/web-app/src/containers/ChatWidthSwitcher.tsx @@ -9,27 +9,31 @@ export function ChatWidthSwitcher() { const { t } = useTranslation() return ( -
+
- - - - - - - - -
-
- ) -} - -export default ProvidersMenu diff --git a/web-app/src/containers/SettingsMenu.tsx b/web-app/src/containers/SettingsMenu.tsx index 5d5e3ef5b6..8aea3b5014 100644 --- a/web-app/src/containers/SettingsMenu.tsx +++ b/web-app/src/containers/SettingsMenu.tsx @@ -1,20 +1,56 @@ -import { Link, useMatches } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { route } from '@/constants/routes' import { useTranslation } from '@/i18n/react-i18next-compat' -import { useModelProvider } from '@/hooks/useModelProvider' +import { useState, useEffect } from 'react' +import { + IconChevronDown, + IconChevronRight, + IconMenu2, + IconX, +} from '@tabler/icons-react' +import { useMatches, useNavigate } from '@tanstack/react-router' +import { cn } from '@/lib/utils' + import { useGeneralSetting } from '@/hooks/useGeneralSetting' +import { useModelProvider } from '@/hooks/useModelProvider' +import { getProviderTitle } from '@/lib/utils' +import ProvidersAvatar from '@/containers/ProvidersAvatar' const SettingsMenu = () => { const { t } = useTranslation() - const { providers } = useModelProvider() - const { experimentalFeatures } = useGeneralSetting() - const firstItemProvider = - providers.length > 0 ? providers[0].provider : 'llama.cpp' + const [expandedProviders, setExpandedProviders] = useState(false) + const [isMenuOpen, setIsMenuOpen] = useState(false) const matches = useMatches() - const isActive = matches.some( + const navigate = useNavigate() + + const { experimentalFeatures } = useGeneralSetting() + const { providers } = useModelProvider() + + // Filter providers that have active API keys (or are llama.cpp which doesn't need one) + const activeProviders = providers.filter((provider) => provider.active) + + // Check if current route has a providerName parameter and expand providers submenu + useEffect(() => { + const hasProviderName = matches.some( + (match) => + match.routeId === '/settings/providers/$providerName' && + 'providerName' in match.params + ) + const isProvidersRoute = matches.some( + (match) => match.routeId === '/settings/providers/' + ) + if (hasProviderName || isProvidersRoute) { + setExpandedProviders(true) + } + }, [matches]) + + // Check if we're in the setup remote provider step + const stepSetupRemoteProvider = matches.some( (match) => - match.routeId === '/settings/providers/$providerName' && - 'providerName' in match.params + match.search && + typeof match.search === 'object' && + 'step' in match.search && + match.search.step === 'setup_remote_provider' ) const menuSettings = [ @@ -30,6 +66,11 @@ const SettingsMenu = () => { title: 'common:privacy', route: route.settings.privacy, }, + { + title: 'common:modelProviders', + route: route.settings.model_providers, + hasSubMenu: activeProviders.length > 0, + }, { title: 'common:keyboardShortcuts', route: route.settings.shortcuts, @@ -61,52 +102,113 @@ const SettingsMenu = () => { }, ] - return ( -
-
- {menuSettings.map((menu, index) => { - // Render the menu item - const menuItem = ( - - {t(menu.title)} - - ) + const toggleProvidersExpansion = () => { + setExpandedProviders(!expandedProviders) + } - if (index === 2) { - return ( -
- {menuItem} + const toggleMenu = () => { + setIsMenuOpen(!isMenuOpen) + } + + return ( + <> + +
+
+ {menuSettings.map((menu) => ( +
+ +
+ {t(menu.title)} + {menu.hasSubMenu && ( + + )} +
+ - {/* Model Providers Link with default parameter */} - {isActive ? ( -
- {t('common:modelProviders')} -
- ) : ( - - - {t('common:modelProviders')} - - - )} -
- ) - } + {/* Sub-menu for model providers */} + {menu.hasSubMenu && expandedProviders && ( +
+ {activeProviders.map((provider) => { + const isActive = matches.some( + (match) => + match.routeId === '/settings/providers/$providerName' && + 'providerName' in match.params && + match.params.providerName === provider.provider + ) - // For other menu items, just render them normally - return menuItem - })} + return ( +
+ +
+ ) + })} +
+ )} +
+ ))} +
-
+ ) } diff --git a/web-app/src/containers/ThreadList.tsx b/web-app/src/containers/ThreadList.tsx index bd3825eeea..afafe6bc2c 100644 --- a/web-app/src/containers/ThreadList.tsx +++ b/web-app/src/containers/ThreadList.tsx @@ -105,8 +105,13 @@ const SortableItem = memo(({ thread }: { thread: Thread }) => { {...attributes} {...listeners} onClick={handleClick} + onContextMenu={(e) => { + e.preventDefault() + e.stopPropagation() + setOpenDropdown(true) + }} className={cn( - 'mb-1 rounded hover:bg-left-panel-fg/10 flex items-center justify-between gap-2 px-1.5 group/thread-list transition-all', + 'mb-1 rounded hover:bg-left-panel-fg/10 flex items-center justify-between gap-2 px-1.5 transition-all', isDragging ? 'cursor-move' : 'cursor-pointer', isActive && 'bg-left-panel-fg/10' )} @@ -122,7 +127,7 @@ const SortableItem = memo(({ thread }: { thread: Thread }) => { { e.preventDefault() e.stopPropagation() diff --git a/web-app/src/hooks/useLeftPanel.ts b/web-app/src/hooks/useLeftPanel.ts index 46440e0e9a..69f999343c 100644 --- a/web-app/src/hooks/useLeftPanel.ts +++ b/web-app/src/hooks/useLeftPanel.ts @@ -4,14 +4,18 @@ import { localStorageKey } from '@/constants/localStorage' type LeftPanelStoreState = { open: boolean + size: number setLeftPanel: (value: boolean) => void + setLeftPanelSize: (value: number) => void } export const useLeftPanel = create()( persist( (set) => ({ open: true, + size: 20, // Default size of 20% setLeftPanel: (value) => set({ open: value }), + setLeftPanelSize: (value) => set({ size: value }), }), { name: localStorageKey.LeftPanel, diff --git a/web-app/src/routeTree.gen.ts b/web-app/src/routeTree.gen.ts index 52782cb2ec..bbd3db3912 100644 --- a/web-app/src/routeTree.gen.ts +++ b/web-app/src/routeTree.gen.ts @@ -27,6 +27,7 @@ import { Route as SettingsGeneralImport } from './routes/settings/general' import { Route as SettingsExtensionsImport } from './routes/settings/extensions' import { Route as SettingsAppearanceImport } from './routes/settings/appearance' import { Route as LocalApiServerLogsImport } from './routes/local-api-server/logs' +import { Route as SettingsProvidersIndexImport } from './routes/settings/providers/index' import { Route as SettingsProvidersProviderNameImport } from './routes/settings/providers/$providerName' // Create/Update Routes @@ -127,6 +128,12 @@ const LocalApiServerLogsRoute = LocalApiServerLogsImport.update({ getParentRoute: () => rootRoute, } as any) +const SettingsProvidersIndexRoute = SettingsProvidersIndexImport.update({ + id: '/settings/providers/', + path: '/settings/providers/', + getParentRoute: () => rootRoute, +} as any) + const SettingsProvidersProviderNameRoute = SettingsProvidersProviderNameImport.update({ id: '/settings/providers/$providerName', @@ -257,6 +264,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SettingsProvidersProviderNameImport parentRoute: typeof rootRoute } + '/settings/providers/': { + id: '/settings/providers/' + path: '/settings/providers' + fullPath: '/settings/providers' + preLoaderRoute: typeof SettingsProvidersIndexImport + parentRoute: typeof rootRoute + } } } @@ -280,6 +294,7 @@ export interface FileRoutesByFullPath { '/settings/shortcuts': typeof SettingsShortcutsRoute '/threads/$threadId': typeof ThreadsThreadIdRoute '/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute + '/settings/providers': typeof SettingsProvidersIndexRoute } export interface FileRoutesByTo { @@ -300,6 +315,7 @@ export interface FileRoutesByTo { '/settings/shortcuts': typeof SettingsShortcutsRoute '/threads/$threadId': typeof ThreadsThreadIdRoute '/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute + '/settings/providers': typeof SettingsProvidersIndexRoute } export interface FileRoutesById { @@ -321,6 +337,7 @@ export interface FileRoutesById { '/settings/shortcuts': typeof SettingsShortcutsRoute '/threads/$threadId': typeof ThreadsThreadIdRoute '/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute + '/settings/providers/': typeof SettingsProvidersIndexRoute } export interface FileRouteTypes { @@ -343,6 +360,7 @@ export interface FileRouteTypes { | '/settings/shortcuts' | '/threads/$threadId' | '/settings/providers/$providerName' + | '/settings/providers' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -362,6 +380,7 @@ export interface FileRouteTypes { | '/settings/shortcuts' | '/threads/$threadId' | '/settings/providers/$providerName' + | '/settings/providers' id: | '__root__' | '/' @@ -381,6 +400,7 @@ export interface FileRouteTypes { | '/settings/shortcuts' | '/threads/$threadId' | '/settings/providers/$providerName' + | '/settings/providers/' fileRoutesById: FileRoutesById } @@ -402,6 +422,7 @@ export interface RootRouteChildren { SettingsShortcutsRoute: typeof SettingsShortcutsRoute ThreadsThreadIdRoute: typeof ThreadsThreadIdRoute SettingsProvidersProviderNameRoute: typeof SettingsProvidersProviderNameRoute + SettingsProvidersIndexRoute: typeof SettingsProvidersIndexRoute } const rootRouteChildren: RootRouteChildren = { @@ -422,6 +443,7 @@ const rootRouteChildren: RootRouteChildren = { SettingsShortcutsRoute: SettingsShortcutsRoute, ThreadsThreadIdRoute: ThreadsThreadIdRoute, SettingsProvidersProviderNameRoute: SettingsProvidersProviderNameRoute, + SettingsProvidersIndexRoute: SettingsProvidersIndexRoute, } export const routeTree = rootRoute @@ -450,7 +472,8 @@ export const routeTree = rootRoute "/settings/privacy", "/settings/shortcuts", "/threads/$threadId", - "/settings/providers/$providerName" + "/settings/providers/$providerName", + "/settings/providers/" ] }, "/": { @@ -503,6 +526,9 @@ export const routeTree = rootRoute }, "/settings/providers/$providerName": { "filePath": "settings/providers/$providerName.tsx" + }, + "/settings/providers/": { + "filePath": "settings/providers/index.tsx" } } } diff --git a/web-app/src/routes/__root.tsx b/web-app/src/routes/__root.tsx index d6383f394f..a1ade841e0 100644 --- a/web-app/src/routes/__root.tsx +++ b/web-app/src/routes/__root.tsx @@ -20,6 +20,13 @@ import { cn } from '@/lib/utils' import ToolApproval from '@/containers/dialogs/ToolApproval' import { TranslationProvider } from '@/i18n/TranslationContext' import OutOfContextPromiseModal from '@/containers/dialogs/OutOfContextDialog' +import { useSmallScreen } from '@/hooks/useMediaQuery' +import { + ResizablePanelGroup, + ResizablePanel, + ResizableHandle, +} from '@/components/ui/resizable' +import { useCallback } from 'react' export const Route = createRootRoute({ component: RootLayout, @@ -27,7 +34,33 @@ export const Route = createRootRoute({ const AppLayout = () => { const { productAnalyticPrompt } = useAnalytic() - const { open: isLeftPanelOpen } = useLeftPanel() + const { + open: isLeftPanelOpen, + setLeftPanel, + size: leftPanelSize, + setLeftPanelSize, + } = useLeftPanel() + const isSmallScreen = useSmallScreen() + + // Minimum width threshold for auto-close (10% of screen width) + const MIN_PANEL_WIDTH_THRESHOLD = 14 + + // Handle panel size changes + const handlePanelLayout = useCallback( + (sizes: number[]) => { + if (sizes.length > 0) { + const newSize = sizes[0] + + // Close panel if resized below minimum threshold + if (newSize < MIN_PANEL_WIDTH_THRESHOLD) { + setLeftPanel(false) + } else { + setLeftPanelSize(newSize) + } + } + }, + [setLeftPanelSize, setLeftPanel] + ) return ( @@ -37,22 +70,56 @@ const AppLayout = () => { {/* Fake absolute panel top to enable window drag */}
-
- {/* left content panel - only show if not logs route */} - - {/* Main content panel */} -
-
- + {/* Left Panel */} + +
+ +
+
+ + {/* Resize Handle */} + + + {/* Main Content Panel */} + +
+
+ +
+
+
+ + ) : ( +
+ {/* left content panel - only show if not logs route */} + + + {/* Main content panel */} +
+
+ +
-
+ )} {productAnalyticPrompt && } diff --git a/web-app/src/routes/hub.tsx b/web-app/src/routes/hub.tsx index 5ac51b1af1..8fbb507229 100644 --- a/web-app/src/routes/hub.tsx +++ b/web-app/src/routes/hub.tsx @@ -259,11 +259,16 @@ function Hub() {
)} {isDownloaded ? ( - ) : (
} - description={ + descriptionOutside={
{t('mcp-servers:command')}: {config.command} diff --git a/web-app/src/routes/settings/providers/$providerName.tsx b/web-app/src/routes/settings/providers/$providerName.tsx index 60254cf65c..d152609081 100644 --- a/web-app/src/routes/settings/providers/$providerName.tsx +++ b/web-app/src/routes/settings/providers/$providerName.tsx @@ -1,9 +1,8 @@ import { Card, CardItem } from '@/containers/Card' import HeaderPage from '@/containers/HeaderPage' -import ProvidersMenu from '@/containers/ProvidersMenu' +import SettingsMenu from '@/containers/SettingsMenu' import { useModelProvider } from '@/hooks/useModelProvider' import { cn, getProviderTitle } from '@/lib/utils' -import { Switch } from '@/components/ui/switch' import { open } from '@tauri-apps/plugin-dialog' import { getActiveModels, @@ -228,23 +227,13 @@ function ProviderDetail() {

{t('common:settings')}

-
- -
+

{getProviderTitle(providerName)}

- { - if (provider) { - updateProvider(providerName, { ...provider, active: e }) - } - }} - />
-

{model.id}

+

+ {model.id} +

} diff --git a/web-app/src/routes/settings/providers/index.tsx b/web-app/src/routes/settings/providers/index.tsx new file mode 100644 index 0000000000..163f829514 --- /dev/null +++ b/web-app/src/routes/settings/providers/index.tsx @@ -0,0 +1,187 @@ +import { createFileRoute } from '@tanstack/react-router' +import { route } from '@/constants/routes' +import SettingsMenu from '@/containers/SettingsMenu' +import HeaderPage from '@/containers/HeaderPage' +import { Button } from '@/components/ui/button' +import { Card, CardItem } from '@/containers/Card' +import { useTranslation } from '@/i18n/react-i18next-compat' +import { useModelProvider } from '@/hooks/useModelProvider' +import { useNavigate } from '@tanstack/react-router' +import { IconCirclePlus, IconSettings } from '@tabler/icons-react' +import { getProviderTitle } from '@/lib/utils' +import ProvidersAvatar from '@/containers/ProvidersAvatar' +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +import { Input } from '@/components/ui/input' +import { Switch } from '@/components/ui/switch' +import { useCallback, useState } from 'react' +import { openAIProviderSettings } from '@/mock/data' +import cloneDeep from 'lodash/cloneDeep' +import { toast } from 'sonner' + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const Route = createFileRoute(route.settings.model_providers as any)({ + component: ModelProviders, +}) + +function ModelProviders() { + const { t } = useTranslation() + const { providers, addProvider, updateProvider } = useModelProvider() + const navigate = useNavigate() + const [name, setName] = useState('') + + const createProvider = useCallback(() => { + if (providers.some((e) => e.provider.toLowerCase() === name.toLowerCase())) { + toast.error(t('providerAlreadyExists', { name })) + return + } + const newProvider = { + provider: name, + active: true, + models: [], + settings: cloneDeep(openAIProviderSettings) as ProviderSetting[], + api_key: '', + base_url: 'https://api.openai.com/v1', + } + addProvider(newProvider) + setTimeout(() => { + navigate({ + to: route.settings.providers, + params: { + providerName: name, + }, + }) + }, 0) + }, [providers, name, addProvider, t, navigate]) + + return ( +
+ +

{t('common:settings')}

+
+
+ +
+
+ {/* Model Providers */} + + + {t('common:modelProviders')} + + + + + + + + + {t('provider:addOpenAIProvider')} + + setName(e.target.value)} + className="mt-2" + placeholder={t('provider:enterNameForProvider')} + onKeyDown={(e) => { + // Prevent key from being captured by parent components + e.stopPropagation() + }} + /> + + + + + + + + + + + +
+ } + > + {providers.map((provider, index) => ( + + +
+

+ {getProviderTitle(provider.provider)} +

+

+ {provider.models.length} Models +

+
+
+ } + actions={ +
+ {provider.active && ( + + )} + { + updateProvider(provider.provider, { + ...provider, + active: e, + }) + }} + /> +
+ } + /> + ))} + +
+
+
+
+ ) +} diff --git a/web-app/src/routes/threads/$threadId.tsx b/web-app/src/routes/threads/$threadId.tsx index c1726408c3..38ad8927d6 100644 --- a/web-app/src/routes/threads/$threadId.tsx +++ b/web-app/src/routes/threads/$threadId.tsx @@ -226,7 +226,7 @@ function ThreadDetail() { return (
@@ -247,7 +247,10 @@ function ThreadDetail() {
) })} - +
=7.10.0" + react: ">=16.9.0" + react-dom: ">=16.9.0" + checksum: 10c0/45d1035af5844b35988ebb2f13adc64ab9ba135d3008686740ec3d9b23e2bbc64ff0ce6e15dea29c1f02e3972d7fb1b22c5950e6e09c4a30fbc016c993327f26 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0, @ungap/structured-clone@npm:^1.3.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10c0/0fc3097c2540ada1fc340ee56d58d96b5b536a2a0dab6e3ec17d4bfc8c4c86db345f61a375a8185f9da96f01c69678f836a2b57eeaa9e4b8eeafd26428e57b0a + languageName: node + linkType: hard + +"@unrs/resolver-binding-android-arm-eabi@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.9.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-android-arm64@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-android-arm64@npm:1.9.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-arm64@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.9.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-x64@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-darwin-x64@npm:1.9.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-freebsd-x64@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.9.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.9.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.9.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-gnu@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.9.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-musl@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.9.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.9.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.9.2" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-musl@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.9.2" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-s390x-gnu@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.9.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-gnu@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.9.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-musl@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.9.2" + conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" +"@unrs/resolver-binding-wasm32-wasi@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.9.2" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - eslint-visitor-keys: "npm:^3.3.0" - checksum: 10c0/7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d + "@napi-rs/wasm-runtime": "npm:^0.2.11" + conditions: cpu=wasm32 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.31.0": - version: 8.31.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.31.0" - dependencies: - "@typescript-eslint/types": "npm:8.31.0" - eslint-visitor-keys: "npm:^4.2.0" - checksum: 10c0/e41e2a9e287d11232cda6126377d1df4de69c6e9dc2a14058819cff15280ec654a3877886a6806728196f299766cfbb0b299eb021c2ce168eb15dff5eb07b51b +"@unrs/resolver-binding-win32-arm64-msvc@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.9.2" + conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@uiw/react-textarea-code-editor@npm:^3.1.1": - version: 3.1.1 - resolution: "@uiw/react-textarea-code-editor@npm:3.1.1" - dependencies: - "@babel/runtime": "npm:^7.18.6" - rehype: "npm:~13.0.0" - rehype-prism-plus: "npm:2.0.0" - peerDependencies: - "@babel/runtime": ">=7.10.0" - react: ">=16.9.0" - react-dom: ">=16.9.0" - checksum: 10c0/45d1035af5844b35988ebb2f13adc64ab9ba135d3008686740ec3d9b23e2bbc64ff0ce6e15dea29c1f02e3972d7fb1b22c5950e6e09c4a30fbc016c993327f26 +"@unrs/resolver-binding-win32-ia32-msvc@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.9.2" + conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0": - version: 1.3.0 - resolution: "@ungap/structured-clone@npm:1.3.0" - checksum: 10c0/0fc3097c2540ada1fc340ee56d58d96b5b536a2a0dab6e3ec17d4bfc8c4c86db345f61a375a8185f9da96f01c69678f836a2b57eeaa9e4b8eeafd26428e57b0a +"@unrs/resolver-binding-win32-x64-msvc@npm:1.9.2": + version: 1.9.2 + resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.9.2" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -6969,7 +7662,7 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.0.2": +"acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1": version: 8.3.4 resolution: "acorn-walk@npm:8.3.4" dependencies: @@ -6996,6 +7689,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.4.1": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" + bin: + acorn: bin/acorn + checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec + languageName: node + linkType: hard + "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -7043,7 +7745,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1": +"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -7075,7 +7777,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": +"ansi-styles@npm:^5.0.0, ansi-styles@npm:^5.2.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" checksum: 10c0/9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df @@ -7106,7 +7808,7 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": +"anymatch@npm:^3.0.3, anymatch@npm:^3.1.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: @@ -7116,6 +7818,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 10c0/070ff801a9d236a6caa647507bdcc7034530604844d64408149a26b9e87c2f97650055c0f049abd1efc024b334635c01f29e0b632b371ac3f26130f4cf65997a + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -7329,20 +8038,20 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "babel-jest@npm:29.7.0" +"babel-jest@npm:30.0.2": + version: 30.0.2 + resolution: "babel-jest@npm:30.0.2" dependencies: - "@jest/transform": "npm:^29.7.0" - "@types/babel__core": "npm:^7.1.14" - babel-plugin-istanbul: "npm:^6.1.1" - babel-preset-jest: "npm:^29.6.3" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" + "@jest/transform": "npm:30.0.2" + "@types/babel__core": "npm:^7.20.5" + babel-plugin-istanbul: "npm:^7.0.0" + babel-preset-jest: "npm:30.0.1" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" slash: "npm:^3.0.0" peerDependencies: - "@babel/core": ^7.8.0 - checksum: 10c0/2eda9c1391e51936ca573dd1aedfee07b14c59b33dbe16ef347873ddd777bcf6e2fc739681e9e9661ab54ef84a3109a03725be2ac32cd2124c07ea4401cbe8c1 + "@babel/core": ^7.11.0 + checksum: 10c0/416deec120eea3f870b45166abc8a30ea29b9235d1acb4a2e50a3b7d623f401589621fa6502dcd4abfffbfaa506eccf20dbbef2c5d0eeac1df9344ec8d8de272 languageName: node linkType: hard @@ -7359,19 +8068,31 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-plugin-jest-hoist@npm:29.6.3" +"babel-plugin-istanbul@npm:^7.0.0": + version: 7.0.0 + resolution: "babel-plugin-istanbul@npm:7.0.0" dependencies: - "@babel/template": "npm:^7.3.3" - "@babel/types": "npm:^7.3.3" - "@types/babel__core": "npm:^7.1.14" - "@types/babel__traverse": "npm:^7.0.6" - checksum: 10c0/7e6451caaf7dce33d010b8aafb970e62f1b0c0b57f4978c37b0d457bbcf0874d75a395a102daf0bae0bd14eafb9f6e9a165ee5e899c0a4f1f3bb2e07b304ed2e + "@babel/helper-plugin-utils": "npm:^7.0.0" + "@istanbuljs/load-nyc-config": "npm:^1.0.0" + "@istanbuljs/schema": "npm:^0.1.3" + istanbul-lib-instrument: "npm:^6.0.2" + test-exclude: "npm:^6.0.0" + checksum: 10c0/79c37bd59ea9bcb16218e874993621e24048776fac7ee72eabe78f0909200851bdb93b32f6eba5b463206f15a1ee7ad40a725af8447952321ae1fdf14e740fe9 languageName: node linkType: hard -"babel-preset-current-node-syntax@npm:^1.0.0": +"babel-plugin-jest-hoist@npm:30.0.1": + version: 30.0.1 + resolution: "babel-plugin-jest-hoist@npm:30.0.1" + dependencies: + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.27.3" + "@types/babel__core": "npm:^7.20.5" + checksum: 10c0/49087f45c8ac359d68c622f4bd471300376b0ca2b6bd6ecaa1bd254ea87eda8fa3ce6144848e3bbabad337d276474a47e2ac3f6272f82e1f2337924ff49a02bd + languageName: node + linkType: hard + +"babel-preset-current-node-syntax@npm:^1.0.0, babel-preset-current-node-syntax@npm:^1.1.0": version: 1.1.0 resolution: "babel-preset-current-node-syntax@npm:1.1.0" dependencies: @@ -7396,15 +8117,15 @@ __metadata: languageName: node linkType: hard -"babel-preset-jest@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-preset-jest@npm:29.6.3" +"babel-preset-jest@npm:30.0.1": + version: 30.0.1 + resolution: "babel-preset-jest@npm:30.0.1" dependencies: - babel-plugin-jest-hoist: "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" + babel-plugin-jest-hoist: "npm:30.0.1" + babel-preset-current-node-syntax: "npm:^1.1.0" peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/ec5fd0276b5630b05f0c14bb97cc3815c6b31600c683ebb51372e54dcb776cff790bdeeabd5b8d01ede375a040337ccbf6a3ccd68d3a34219125945e167ad943 + "@babel/core": ^7.11.0 + checksum: 10c0/33da0094965929b1742b02e55272b544f189cd487d55bbba60e68d96d62d48f466264fe51f65950454829d4f2271541f2433e1c1c5e6a7ff5b9e91f1303471b7 languageName: node linkType: hard @@ -7923,7 +8644,7 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": +"callsites@npm:^3.0.0, callsites@npm:^3.1.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 @@ -7954,7 +8675,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.2.0": +"camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 @@ -8147,6 +8868,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^4.2.0": + version: 4.2.0 + resolution: "ci-info@npm:4.2.0" + checksum: 10c0/37a2f4b6a213a5cf835890eb0241f0d5b022f6cfefde58a69e9af8e3a0e71e06d6ad7754b0d4efb9cd2613e58a7a33996d71b56b0d04242722e86666f3f3d058 + languageName: node + linkType: hard + "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": version: 1.0.6 resolution: "cipher-base@npm:1.0.6" @@ -8164,6 +8892,13 @@ __metadata: languageName: node linkType: hard +"cjs-module-lexer@npm:^2.1.0": + version: 2.1.0 + resolution: "cjs-module-lexer@npm:2.1.0" + checksum: 10c0/91cf28686dc3948e4a06dfa03a2fccb14b7a97471ffe7ae0124f62060ddf2de28e8e997f60007babe6e122b1b06a47c01a1b72cc015f185824d9cac3ccfa5533 + languageName: node + linkType: hard + "class-utils@npm:^0.3.5": version: 0.3.6 resolution: "class-utils@npm:0.3.6" @@ -8260,7 +8995,7 @@ __metadata: languageName: node linkType: hard -"collect-v8-coverage@npm:^1.0.0": +"collect-v8-coverage@npm:^1.0.0, collect-v8-coverage@npm:^1.0.2": version: 1.0.2 resolution: "collect-v8-coverage@npm:1.0.2" checksum: 10c0/ed7008e2e8b6852c5483b444a3ae6e976e088d4335a85aa0a9db2861c5f1d31bd2d7ff97a60469b3388deeba661a619753afbe201279fb159b4b9548ab8269a1 @@ -8337,6 +9072,13 @@ __metadata: languageName: node linkType: hard +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: 10c0/c4a74294e1b1570f4a8ab435285d185a03976c323caa16359053e749db4fde44e3e6586c29cd051100335e11895767cbbd27ea389108e327d62f38daf4548fdb + languageName: node + linkType: hard + "component-emitter@npm:^1.2.1": version: 1.3.1 resolution: "component-emitter@npm:1.3.1" @@ -8514,24 +9256,7 @@ __metadata: languageName: node linkType: hard -"create-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "create-jest@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - prompts: "npm:^2.0.1" - bin: - create-jest: bin/create-jest.js - checksum: 10c0/e7e54c280692470d3398f62a6238fd396327e01c6a0757002833f06d00afc62dd7bfe04ff2b9cd145264460e6b4d1eb8386f2925b7e567f97939843b7b0e812f - languageName: node - linkType: hard - -"create-require@npm:^1.1.1": +"create-require@npm:^1.1.0, create-require@npm:^1.1.1": version: 1.1.1 resolution: "create-require@npm:1.1.1" checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 @@ -8656,6 +9381,13 @@ __metadata: languageName: node linkType: hard +"date-format@npm:^4.0.14": + version: 4.0.14 + resolution: "date-format@npm:4.0.14" + checksum: 10c0/1c67a4d77c677bb880328c81d81f5b9ed7fbf672bdaff74e5a0f7314b21188f3a829b06acf120c70cc1df876a7724e3e5c23d511e86d64656a3035a76ac3930b + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.6": version: 4.4.0 resolution: "debug@npm:4.4.0" @@ -8800,15 +9532,15 @@ __metadata: languageName: node linkType: hard -"dedent@npm:^1.0.0": - version: 1.5.3 - resolution: "dedent@npm:1.5.3" +"dedent@npm:^1.6.0": + version: 1.6.0 + resolution: "dedent@npm:1.6.0" peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - checksum: 10c0/d94bde6e6f780be4da4fd760288fcf755ec368872f4ac5218197200d86430aeb8d90a003a840bff1c20221188e3f23adced0119cb811c6873c70d0ac66d12832 + checksum: 10c0/671b8f5e390dd2a560862c4511dd6d2638e71911486f78cb32116551f8f2aa6fcaf50579ffffb2f866d46b5b80fd72470659ca5760ede8f967619ef7df79e8a5 languageName: node linkType: hard @@ -8833,7 +9565,7 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1": +"deepmerge@npm:^4.3.1": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044 @@ -8928,7 +9660,7 @@ __metadata: languageName: node linkType: hard -"detect-newline@npm:^3.0.0": +"detect-newline@npm:^3.0.0, detect-newline@npm:^3.1.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" checksum: 10c0/c38cfc8eeb9fda09febb44bcd85e467c970d4e3bf526095394e5a4f18bc26dd0cf6b22c69c1fa9969261521c593836db335c2795218f6d781a512aea2fb8209d @@ -8965,6 +9697,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: 10c0/81b91f9d39c4eaca068eb0c1eb0e4afbdc5bb2941d197f513dd596b820b956fef43485876226d65d497bebc15666aa2aa82c679e84f65d5f2bfbf14ee46e32c1 + languageName: node + linkType: hard + "diff@npm:^7.0.0": version: 7.0.0 resolution: "diff@npm:7.0.0" @@ -9753,7 +10492,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -9770,10 +10509,10 @@ __metadata: languageName: node linkType: hard -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: 10c0/71d2ad9b36bc25bb8b104b17e830b40a08989be7f7d100b13269aaae7c3784c3e6e1e88a797e9e87523993a25ba27c8958959a554535370672cfb4d824af8989 +"exit-x@npm:^0.2.2": + version: 0.2.2 + resolution: "exit-x@npm:0.2.2" + checksum: 10c0/212a7a095ca5540e9581f1ef2d1d6a40df7a6027c8cc96e78ce1d16b86d1a88326d4a0eff8dff2b5ec1e68bb0c1edd5d0dfdde87df1869bf7514d4bc6a5cbd72 languageName: node linkType: hard @@ -9817,7 +10556,21 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0, expect@npm:^29.7.0": +"expect@npm:30.0.3, expect@npm:^30.0.0": + version: 30.0.3 + resolution: "expect@npm:30.0.3" + dependencies: + "@jest/expect-utils": "npm:30.0.3" + "@jest/get-type": "npm:30.0.1" + jest-matcher-utils: "npm:30.0.3" + jest-message-util: "npm:30.0.2" + jest-mock: "npm:30.0.2" + jest-util: "npm:30.0.2" + checksum: 10c0/6bb88a42d6fcacbd0b25d4f90c389e2e439cd1d3b68f4b708582bcfe4a9575d1584edb554921e21230bc484ae55f8d639fc8186545ba9e6070a83e82a18655d8 + languageName: node + linkType: hard + +"expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" dependencies: @@ -10012,7 +10765,7 @@ __metadata: languageName: node linkType: hard -"fb-watchman@npm:^2.0.0": +"fb-watchman@npm:^2.0.0, fb-watchman@npm:^2.0.2": version: 2.0.2 resolution: "fb-watchman@npm:2.0.2" dependencies: @@ -10175,6 +10928,16 @@ __metadata: languageName: node linkType: hard +"find-cache-dir@npm:^5.0.0": + version: 5.0.0 + resolution: "find-cache-dir@npm:5.0.0" + dependencies: + common-path-prefix: "npm:^3.0.0" + pkg-dir: "npm:^7.0.0" + checksum: 10c0/e6403b35aaf862898aefadbe3ee27246583a69adcef21cd79b9262be407d1ac85b21a7e1c1d41712eae39c6d8a8ac297fd78123b5b7aea13f0f046744aa02453 + languageName: node + linkType: hard + "find-index@npm:^0.1.1": version: 0.1.1 resolution: "find-index@npm:0.1.1" @@ -10212,6 +10975,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: "npm:^7.1.0" + path-exists: "npm:^5.0.0" + checksum: 10c0/07e0314362d316b2b13f7f11ea4692d5191e718ca3f7264110127520f3347996349bf9e16805abae3e196805814bc66ef4bff2b8904dc4a6476085fc9b0eba07 + languageName: node + linkType: hard + "flairup@npm:1.0.0": version: 1.0.0 resolution: "flairup@npm:1.0.0" @@ -10240,7 +11013,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.2.9": +"flatted@npm:^3.2.7, flatted@npm:^3.2.9": version: 3.3.3 resolution: "flatted@npm:3.3.3" checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 @@ -10282,7 +11055,7 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0": +"foreground-child@npm:^3.1.0, foreground-child@npm:^3.1.1, foreground-child@npm:^3.3.1": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" dependencies: @@ -10489,7 +11262,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": +"fsevents@npm:^2.3.2, fsevents@npm:^2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -10509,7 +11282,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A^2.3.3#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -10724,6 +11497,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^11.0.0": + version: 11.0.3 + resolution: "glob@npm:11.0.3" + dependencies: + foreground-child: "npm:^3.3.1" + jackspeak: "npm:^4.1.1" + minimatch: "npm:^10.0.3" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^2.0.0" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/7d24457549ec2903920dfa3d8e76850e7c02aa709122f0164b240c712f5455c0b457e6f2a1eee39344c6148e39895be8094ae8cfef7ccc3296ed30bce250c661 + languageName: node + linkType: hard + "glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -10863,7 +11652,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.2, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.2, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -11516,6 +12305,13 @@ __metadata: languageName: node linkType: hard +"immediate@npm:~3.0.5": + version: 3.0.6 + resolution: "immediate@npm:3.0.6" + checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1": version: 3.3.1 resolution: "import-fresh@npm:3.3.1" @@ -11526,7 +12322,7 @@ __metadata: languageName: node linkType: hard -"import-local@npm:^3.0.2": +"import-local@npm:^3.2.0": version: 3.2.0 resolution: "import-local@npm:3.2.0" dependencies: @@ -11820,7 +12616,7 @@ __metadata: languageName: node linkType: hard -"is-generator-fn@npm:^2.0.0": +"is-generator-fn@npm:^2.1.0": version: 2.1.0 resolution: "is-generator-fn@npm:2.1.0" checksum: 10c0/2957cab387997a466cd0bf5c1b6047bd21ecb32bdcfd8996b15747aa01002c1c88731802f1b3d34ac99f4f6874b626418bd118658cf39380fe5fff32a3af9c4d @@ -12140,7 +12936,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^6.0.0": +"istanbul-lib-instrument@npm:^6.0.0, istanbul-lib-instrument@npm:^6.0.2": version: 6.0.3 resolution: "istanbul-lib-instrument@npm:6.0.3" dependencies: @@ -12164,14 +12960,14 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" +"istanbul-lib-source-maps@npm:^5.0.0": + version: 5.0.6 + resolution: "istanbul-lib-source-maps@npm:5.0.6" dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.23" debug: "npm:^4.1.1" istanbul-lib-coverage: "npm:^3.0.0" - source-map: "npm:^0.6.1" - checksum: 10c0/19e4cc405016f2c906dff271a76715b3e881fa9faeb3f09a86cb99b8512b3a5ed19cadfe0b54c17ca0e54c1142c9c6de9330d65506e35873994e06634eebeb66 + checksum: 10c0/ffe75d70b303a3621ee4671554f306e0831b16f39ab7f4ab52e54d356a5d33e534d97563e318f1333a6aae1d42f91ec49c76b6cd3f3fb378addcb5c81da0255f languageName: node linkType: hard @@ -12208,6 +13004,15 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^4.1.1": + version: 4.1.1 + resolution: "jackspeak@npm:4.1.1" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + checksum: 10c0/84ec4f8e21d6514db24737d9caf65361511f75e5e424980eebca4199f400874f45e562ac20fa8aeb1dd20ca2f3f81f0788b6e9c3e64d216a5794fd6f30e0e042 + languageName: node + linkType: hard + "jake@npm:^10.8.5": version: 10.9.2 resolution: "jake@npm:10.9.2" @@ -12232,7 +13037,7 @@ __metadata: cross-env: "npm:^7.0.3" download-cli: "npm:^1.1.1" husky: "npm:^9.1.5" - jest: "npm:^29.7.0" + jest: "npm:^30.0.3" jest-environment-jsdom: "npm:^29.7.0" rimraf: "npm:^3.0.2" run-script-os: "npm:^1.1.6" @@ -12242,106 +13047,122 @@ __metadata: languageName: unknown linkType: soft -"jest-changed-files@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-changed-files@npm:29.7.0" +"jest-changed-files@npm:30.0.2": + version: 30.0.2 + resolution: "jest-changed-files@npm:30.0.2" dependencies: - execa: "npm:^5.0.0" - jest-util: "npm:^29.7.0" + execa: "npm:^5.1.1" + jest-util: "npm:30.0.2" p-limit: "npm:^3.1.0" - checksum: 10c0/e071384d9e2f6bb462231ac53f29bff86f0e12394c1b49ccafbad225ce2ab7da226279a8a94f421949920bef9be7ef574fd86aee22e8adfa149be73554ab828b + checksum: 10c0/794c9e47c460974f2303631d9ee44845d03f4ccd5240649a5f736aa94af78fa5931022324ab302c577dad6adb442ed17140dee9b9985bbfa0d43cad3048a7350 languageName: node linkType: hard -"jest-circus@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-circus@npm:29.7.0" +"jest-circus@npm:30.0.3": + version: 30.0.3 + resolution: "jest-circus@npm:30.0.3" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/environment": "npm:30.0.2" + "@jest/expect": "npm:30.0.3" + "@jest/test-result": "npm:30.0.2" + "@jest/types": "npm:30.0.1" "@types/node": "npm:*" - chalk: "npm:^4.0.0" + chalk: "npm:^4.1.2" co: "npm:^4.6.0" - dedent: "npm:^1.0.0" - is-generator-fn: "npm:^2.0.0" - jest-each: "npm:^29.7.0" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" + dedent: "npm:^1.6.0" + is-generator-fn: "npm:^2.1.0" + jest-each: "npm:30.0.2" + jest-matcher-utils: "npm:30.0.3" + jest-message-util: "npm:30.0.2" + jest-runtime: "npm:30.0.3" + jest-snapshot: "npm:30.0.3" + jest-util: "npm:30.0.2" p-limit: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - pure-rand: "npm:^6.0.0" + pretty-format: "npm:30.0.2" + pure-rand: "npm:^7.0.0" slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10c0/8d15344cf7a9f14e926f0deed64ed190c7a4fa1ed1acfcd81e4cc094d3cc5bf7902ebb7b874edc98ada4185688f90c91e1747e0dfd7ac12463b097968ae74b5e + stack-utils: "npm:^2.0.6" + checksum: 10c0/cb0838cc9f08984614d92c5fe857ea95f1bdff6de4a510a1b228cc9c0513d18bb2db89dcaf55624e754b11d77fb77bdba1fc56c6af34c1534102c498ce058399 languageName: node linkType: hard -"jest-cli@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-cli@npm:29.7.0" +"jest-cli@npm:30.0.3": + version: 30.0.3 + resolution: "jest-cli@npm:30.0.3" dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - create-jest: "npm:^29.7.0" - exit: "npm:^0.1.2" - import-local: "npm:^3.0.2" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - yargs: "npm:^17.3.1" + "@jest/core": "npm:30.0.3" + "@jest/test-result": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + chalk: "npm:^4.1.2" + exit-x: "npm:^0.2.2" + import-local: "npm:^3.2.0" + jest-config: "npm:30.0.3" + jest-util: "npm:30.0.2" + jest-validate: "npm:30.0.2" + yargs: "npm:^17.7.2" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true bin: - jest: bin/jest.js - checksum: 10c0/a658fd55050d4075d65c1066364595962ead7661711495cfa1dfeecf3d6d0a8ffec532f3dbd8afbb3e172dd5fd2fb2e813c5e10256e7cf2fea766314942fb43a + jest: ./bin/jest.js + checksum: 10c0/17925e9e885b00069e06672c221fbe073d1bff1d869f228bcba08ac23bf8d2c258c7211ce4d0e8408ca7d0edf0afb8ae4098e3d0f5da253eed22d385b135ca90 languageName: node linkType: hard -"jest-config@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-config@npm:29.7.0" +"jest-config@npm:30.0.3": + version: 30.0.3 + resolution: "jest-config@npm:30.0.3" dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/test-sequencer": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-jest: "npm:^29.7.0" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - deepmerge: "npm:^4.2.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-circus: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - micromatch: "npm:^4.0.4" + "@babel/core": "npm:^7.27.4" + "@jest/get-type": "npm:30.0.1" + "@jest/pattern": "npm:30.0.1" + "@jest/test-sequencer": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + babel-jest: "npm:30.0.2" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.2.0" + deepmerge: "npm:^4.3.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.11" + jest-circus: "npm:30.0.3" + jest-docblock: "npm:30.0.1" + jest-environment-node: "npm:30.0.2" + jest-regex-util: "npm:30.0.1" + jest-resolve: "npm:30.0.2" + jest-runner: "npm:30.0.3" + jest-util: "npm:30.0.2" + jest-validate: "npm:30.0.2" + micromatch: "npm:^4.0.8" parse-json: "npm:^5.2.0" - pretty-format: "npm:^29.7.0" + pretty-format: "npm:30.0.2" slash: "npm:^3.0.0" strip-json-comments: "npm:^3.1.1" peerDependencies: "@types/node": "*" + esbuild-register: ">=3.4.0" ts-node: ">=9.0.0" peerDependenciesMeta: "@types/node": optional: true + esbuild-register: + optional: true ts-node: optional: true - checksum: 10c0/bab23c2eda1fff06e0d104b00d6adfb1d1aabb7128441899c9bff2247bd26710b050a5364281ce8d52b46b499153bf7e3ee88b19831a8f3451f1477a0246a0f1 + checksum: 10c0/bcde9e0e715bbc12dd36a135d6e081566291b0726ed7b3ac9a1e2ee2ade7c9bcc25d312ef8a649b72b9c99e2ad6661eb843eeb919ba6206f2ec2acccdd1e57d2 + languageName: node + linkType: hard + +"jest-diff@npm:30.0.3": + version: 30.0.3 + resolution: "jest-diff@npm:30.0.3" + dependencies: + "@jest/diff-sequences": "npm:30.0.1" + "@jest/get-type": "npm:30.0.1" + chalk: "npm:^4.1.2" + pretty-format: "npm:30.0.2" + checksum: 10c0/f6aaed30fc99bdca4b8b4505b283ffc78b780aa1bf33670dfbfe439e124721e7f6198c03217f7ed17a22c7d2ca79363afd6a4245643596fa21ae082b6b4ed4f5 languageName: node linkType: hard @@ -12357,6 +13178,15 @@ __metadata: languageName: node linkType: hard +"jest-docblock@npm:30.0.1": + version: 30.0.1 + resolution: "jest-docblock@npm:30.0.1" + dependencies: + detect-newline: "npm:^3.1.0" + checksum: 10c0/f9bad2651db8afa029867ea7a40f422c9d73c67657360297371846a314a40c8786424be00483261df9137499f52c2af28cd458fbd15a7bf7fac8775b4bcd6ee1 + languageName: node + linkType: hard + "jest-docblock@npm:^29.7.0": version: 29.7.0 resolution: "jest-docblock@npm:29.7.0" @@ -12366,16 +13196,16 @@ __metadata: languageName: node linkType: hard -"jest-each@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-each@npm:29.7.0" +"jest-each@npm:30.0.2": + version: 30.0.2 + resolution: "jest-each@npm:30.0.2" dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - pretty-format: "npm:^29.7.0" - checksum: 10c0/f7f9a90ebee80cc688e825feceb2613627826ac41ea76a366fa58e669c3b2403d364c7c0a74d862d469b103c843154f8456d3b1c02b487509a12afa8b59edbb4 + "@jest/get-type": "npm:30.0.1" + "@jest/types": "npm:30.0.1" + chalk: "npm:^4.1.2" + jest-util: "npm:30.0.2" + pretty-format: "npm:30.0.2" + checksum: 10c0/6fff0a470d08ba3f0149c58266b7e938e3e183398f99065fe937290f1297ca254635f0f4bca6196514f756fac0a9759144b1c7f67bef97cc0b7fa0b96304df9e languageName: node linkType: hard @@ -12400,6 +13230,21 @@ __metadata: languageName: node linkType: hard +"jest-environment-node@npm:30.0.2": + version: 30.0.2 + resolution: "jest-environment-node@npm:30.0.2" + dependencies: + "@jest/environment": "npm:30.0.2" + "@jest/fake-timers": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + jest-mock: "npm:30.0.2" + jest-util: "npm:30.0.2" + jest-validate: "npm:30.0.2" + checksum: 10c0/e58515d26f13704c3be6281d029c4fa0902172d2a55751205badf0153630520c4e651f7923577e1ab0dfbb64c4fedb1e4b78622b53b3a8d8e0515c1923f3adc3 + languageName: node + linkType: hard + "jest-environment-node@npm:^29.7.0": version: 29.7.0 resolution: "jest-environment-node@npm:29.7.0" @@ -12421,6 +13266,28 @@ __metadata: languageName: node linkType: hard +"jest-haste-map@npm:30.0.2": + version: 30.0.2 + resolution: "jest-haste-map@npm:30.0.2" + dependencies: + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + anymatch: "npm:^3.1.3" + fb-watchman: "npm:^2.0.2" + fsevents: "npm:^2.3.3" + graceful-fs: "npm:^4.2.11" + jest-regex-util: "npm:30.0.1" + jest-util: "npm:30.0.2" + jest-worker: "npm:30.0.2" + micromatch: "npm:^4.0.8" + walker: "npm:^1.0.8" + dependenciesMeta: + fsevents: + optional: true + checksum: 10c0/6427b6976beb3fd33cae9a516e24f409d0cc0be2afa12a62e95671001a0d0d61662e8b2185027639b2036fe3e3b055e9d9b4dfd2063e787cf2a5d2140da0b80a + languageName: node + linkType: hard + "jest-haste-map@npm:^29.7.0": version: 29.7.0 resolution: "jest-haste-map@npm:29.7.0" @@ -12456,6 +13323,16 @@ __metadata: languageName: node linkType: hard +"jest-leak-detector@npm:30.0.2": + version: 30.0.2 + resolution: "jest-leak-detector@npm:30.0.2" + dependencies: + "@jest/get-type": "npm:30.0.1" + pretty-format: "npm:30.0.2" + checksum: 10c0/1df28475c40b41024adc6e18af0d3dc8d8d318fdbbf5c3560321fea0af2e0784c57f788b5b152efd83274ab6ea8dc3b36662060a83a2a555ffd8cdf7d628ee76 + languageName: node + linkType: hard + "jest-leak-detector@npm:^29.7.0": version: 29.7.0 resolution: "jest-leak-detector@npm:29.7.0" @@ -12466,6 +13343,18 @@ __metadata: languageName: node linkType: hard +"jest-matcher-utils@npm:30.0.3": + version: 30.0.3 + resolution: "jest-matcher-utils@npm:30.0.3" + dependencies: + "@jest/get-type": "npm:30.0.1" + chalk: "npm:^4.1.2" + jest-diff: "npm:30.0.3" + pretty-format: "npm:30.0.2" + checksum: 10c0/4d354f6d8d3992228ba5f0ecc728ec0c46f3693805927253d67e461e754deadc1e1b48ae80918e3f029c22da4abed9aaadb5049da1a1697f6714b0f6076eeafa + languageName: node + linkType: hard + "jest-matcher-utils@npm:^29.7.0": version: 29.7.0 resolution: "jest-matcher-utils@npm:29.7.0" @@ -12478,6 +13367,23 @@ __metadata: languageName: node linkType: hard +"jest-message-util@npm:30.0.2": + version: 30.0.2 + resolution: "jest-message-util@npm:30.0.2" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@jest/types": "npm:30.0.1" + "@types/stack-utils": "npm:^2.0.3" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" + micromatch: "npm:^4.0.8" + pretty-format: "npm:30.0.2" + slash: "npm:^3.0.0" + stack-utils: "npm:^2.0.6" + checksum: 10c0/c010d5b7d86e735e2fb4c4a220f57004349f488f5d4663240a7e9f2694d01b5228136540d55036777fde4227b5e0b56f08885b7f69395b295cab878357b1aeb1 + languageName: node + linkType: hard + "jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" @@ -12495,6 +13401,17 @@ __metadata: languageName: node linkType: hard +"jest-mock@npm:30.0.2": + version: 30.0.2 + resolution: "jest-mock@npm:30.0.2" + dependencies: + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + jest-util: "npm:30.0.2" + checksum: 10c0/7728997c1d654475b88e18b7ba33a2a1b9f89ce33a9082bf2d14dcc3e831f372f80c762e481777886a3a04b4489ea5390ecdeb21c4def57fba5b2c77086a3959 + languageName: node + linkType: hard + "jest-mock@npm:^29.7.0": version: 29.7.0 resolution: "jest-mock@npm:29.7.0" @@ -12506,7 +13423,7 @@ __metadata: languageName: node linkType: hard -"jest-pnp-resolver@npm:^1.2.2": +"jest-pnp-resolver@npm:^1.2.2, jest-pnp-resolver@npm:^1.2.3": version: 1.2.3 resolution: "jest-pnp-resolver@npm:1.2.3" peerDependencies: @@ -12518,6 +13435,13 @@ __metadata: languageName: node linkType: hard +"jest-regex-util@npm:30.0.1": + version: 30.0.1 + resolution: "jest-regex-util@npm:30.0.1" + checksum: 10c0/f30c70524ebde2d1012afe5ffa5691d5d00f7d5ba9e43d588f6460ac6fe96f9e620f2f9b36a02d0d3e7e77bc8efb8b3450ae3b80ac53c8be5099e01bf54f6728 + languageName: node + linkType: hard + "jest-regex-util@npm:^29.6.3": version: 29.6.3 resolution: "jest-regex-util@npm:29.6.3" @@ -12525,13 +13449,29 @@ __metadata: languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve-dependencies@npm:29.7.0" +"jest-resolve-dependencies@npm:30.0.3": + version: 30.0.3 + resolution: "jest-resolve-dependencies@npm:30.0.3" + dependencies: + jest-regex-util: "npm:30.0.1" + jest-snapshot: "npm:30.0.3" + checksum: 10c0/5684e62f05d19c5ab97b2b2262075f056bd48745bf25501671d0b9a03f2a0548ab04370b9cec6e97207d57ead54d706a67ef3254729cacb6d6405ef381cdf511 + languageName: node + linkType: hard + +"jest-resolve@npm:30.0.2": + version: 30.0.2 + resolution: "jest-resolve@npm:30.0.2" dependencies: - jest-regex-util: "npm:^29.6.3" - jest-snapshot: "npm:^29.7.0" - checksum: 10c0/b6e9ad8ae5b6049474118ea6441dfddd385b6d1fc471db0136f7c8fbcfe97137a9665e4f837a9f49f15a29a1deb95a14439b7aec812f3f99d08f228464930f0d + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.0.2" + jest-pnp-resolver: "npm:^1.2.3" + jest-util: "npm:30.0.2" + jest-validate: "npm:30.0.2" + slash: "npm:^3.0.0" + unrs-resolver: "npm:^1.7.11" + checksum: 10c0/33ae69455b1206a926bb6f7dd46cd4b6cbf5e095387078873a05dfb693bef419b93897e052ee68026b31b5e5f537fdcfce42f2d31af0ce7e64a8179ed7882b51 languageName: node linkType: hard @@ -12552,6 +13492,36 @@ __metadata: languageName: node linkType: hard +"jest-runner@npm:30.0.3": + version: 30.0.3 + resolution: "jest-runner@npm:30.0.3" + dependencies: + "@jest/console": "npm:30.0.2" + "@jest/environment": "npm:30.0.2" + "@jest/test-result": "npm:30.0.2" + "@jest/transform": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + chalk: "npm:^4.1.2" + emittery: "npm:^0.13.1" + exit-x: "npm:^0.2.2" + graceful-fs: "npm:^4.2.11" + jest-docblock: "npm:30.0.1" + jest-environment-node: "npm:30.0.2" + jest-haste-map: "npm:30.0.2" + jest-leak-detector: "npm:30.0.2" + jest-message-util: "npm:30.0.2" + jest-resolve: "npm:30.0.2" + jest-runtime: "npm:30.0.3" + jest-util: "npm:30.0.2" + jest-watcher: "npm:30.0.2" + jest-worker: "npm:30.0.2" + p-limit: "npm:^3.1.0" + source-map-support: "npm:0.5.13" + checksum: 10c0/d139ee4ed4f2d7aeefc8c496efc906960e938beadc22dce6167e7270db4e10260092eace6748a6efb7ee2a40e3bd3ee5d60cbefc2a1e3459826cfde69cdb9195 + languageName: node + linkType: hard + "jest-runner@npm:^29.7.0": version: 29.7.0 resolution: "jest-runner@npm:29.7.0" @@ -12581,6 +13551,36 @@ __metadata: languageName: node linkType: hard +"jest-runtime@npm:30.0.3": + version: 30.0.3 + resolution: "jest-runtime@npm:30.0.3" + dependencies: + "@jest/environment": "npm:30.0.2" + "@jest/fake-timers": "npm:30.0.2" + "@jest/globals": "npm:30.0.3" + "@jest/source-map": "npm:30.0.1" + "@jest/test-result": "npm:30.0.2" + "@jest/transform": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + chalk: "npm:^4.1.2" + cjs-module-lexer: "npm:^2.1.0" + collect-v8-coverage: "npm:^1.0.2" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.0.2" + jest-message-util: "npm:30.0.2" + jest-mock: "npm:30.0.2" + jest-regex-util: "npm:30.0.1" + jest-resolve: "npm:30.0.2" + jest-snapshot: "npm:30.0.3" + jest-util: "npm:30.0.2" + slash: "npm:^3.0.0" + strip-bom: "npm:^4.0.0" + checksum: 10c0/01a184b80bf1ae2d6eca280daf37e355b983795e342406de461cf4d45c75ec48a635bf89c08d54fb73f851180e870ef82004fd1f6b335f0329dc07f3bd14a94d + languageName: node + linkType: hard + "jest-runtime@npm:^29.7.0": version: 29.7.0 resolution: "jest-runtime@npm:29.7.0" @@ -12611,6 +13611,35 @@ __metadata: languageName: node linkType: hard +"jest-snapshot@npm:30.0.3": + version: 30.0.3 + resolution: "jest-snapshot@npm:30.0.3" + dependencies: + "@babel/core": "npm:^7.27.4" + "@babel/generator": "npm:^7.27.5" + "@babel/plugin-syntax-jsx": "npm:^7.27.1" + "@babel/plugin-syntax-typescript": "npm:^7.27.1" + "@babel/types": "npm:^7.27.3" + "@jest/expect-utils": "npm:30.0.3" + "@jest/get-type": "npm:30.0.1" + "@jest/snapshot-utils": "npm:30.0.1" + "@jest/transform": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + babel-preset-current-node-syntax: "npm:^1.1.0" + chalk: "npm:^4.1.2" + expect: "npm:30.0.3" + graceful-fs: "npm:^4.2.11" + jest-diff: "npm:30.0.3" + jest-matcher-utils: "npm:30.0.3" + jest-message-util: "npm:30.0.2" + jest-util: "npm:30.0.2" + pretty-format: "npm:30.0.2" + semver: "npm:^7.7.2" + synckit: "npm:^0.11.8" + checksum: 10c0/0af682495b79bc0e640edbb03ada06db073a0784d6a9c0bb11e592afa4d0dca63c63ab485f540e8d1bd7674456418906e194e7f0660cc20107423d4fe11b4d6e + languageName: node + linkType: hard + "jest-snapshot@npm:^29.7.0": version: 29.7.0 resolution: "jest-snapshot@npm:29.7.0" @@ -12639,6 +13668,20 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:30.0.2": + version: 30.0.2 + resolution: "jest-util@npm:30.0.2" + dependencies: + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.2.0" + graceful-fs: "npm:^4.2.11" + picomatch: "npm:^4.0.2" + checksum: 10c0/07de384790b8e5a5925fba5448fa1475790a5b52271fbf99958c18e468da1af940f8b45e330d87766576cf6c5d1f4f41ce51c976483a5079653d9fcdba8aac8e + languageName: node + linkType: hard + "jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" @@ -12653,6 +13696,20 @@ __metadata: languageName: node linkType: hard +"jest-validate@npm:30.0.2": + version: 30.0.2 + resolution: "jest-validate@npm:30.0.2" + dependencies: + "@jest/get-type": "npm:30.0.1" + "@jest/types": "npm:30.0.1" + camelcase: "npm:^6.3.0" + chalk: "npm:^4.1.2" + leven: "npm:^3.1.0" + pretty-format: "npm:30.0.2" + checksum: 10c0/9fd1b4f604851187655353eefe8db25db9638dd312d2e29d58868e626d78925edefe94fe2c8eb63305eefd41e5fe7f8aff334e2db9db5aaddeec866f9f6561d8 + languageName: node + linkType: hard + "jest-validate@npm:^29.7.0": version: 29.7.0 resolution: "jest-validate@npm:29.7.0" @@ -12667,6 +13724,22 @@ __metadata: languageName: node linkType: hard +"jest-watcher@npm:30.0.2": + version: 30.0.2 + resolution: "jest-watcher@npm:30.0.2" + dependencies: + "@jest/test-result": "npm:30.0.2" + "@jest/types": "npm:30.0.1" + "@types/node": "npm:*" + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^4.1.2" + emittery: "npm:^0.13.1" + jest-util: "npm:30.0.2" + string-length: "npm:^4.0.2" + checksum: 10c0/7cb09da5feaa6c5558e5149406bde354c3e227ef692b5371efe4d13cf566d42a157c04a55f3a201d191afb7ebc49be84b1ed5a744f46497d9ecccc323d8963f5 + languageName: node + linkType: hard + "jest-watcher@npm:^29.7.0": version: 29.7.0 resolution: "jest-watcher@npm:29.7.0" @@ -12683,6 +13756,19 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:30.0.2": + version: 30.0.2 + resolution: "jest-worker@npm:30.0.2" + dependencies: + "@types/node": "npm:*" + "@ungap/structured-clone": "npm:^1.3.0" + jest-util: "npm:30.0.2" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.1.1" + checksum: 10c0/d7d237e763a2f1aed4eba07f977490442a7bb085f7ab63163afa88776804c2644cc05a1e32da9d05a4b895ad22b2e939ef01a90ffb3024b53fc8c73b8ad1d3f1 + languageName: node + linkType: hard + "jest-worker@npm:^29.7.0": version: 29.7.0 resolution: "jest-worker@npm:29.7.0" @@ -12695,22 +13781,22 @@ __metadata: languageName: node linkType: hard -"jest@npm:^29.7.0": - version: 29.7.0 - resolution: "jest@npm:29.7.0" +"jest@npm:^30.0.3": + version: 30.0.3 + resolution: "jest@npm:30.0.3" dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - import-local: "npm:^3.0.2" - jest-cli: "npm:^29.7.0" + "@jest/core": "npm:30.0.3" + "@jest/types": "npm:30.0.1" + import-local: "npm:^3.2.0" + jest-cli: "npm:30.0.3" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true bin: - jest: bin/jest.js - checksum: 10c0/f40eb8171cf147c617cc6ada49d062fbb03b4da666cb8d39cdbfb739a7d75eea4c3ca150fb072d0d273dce0c753db4d0467d54906ad0293f59c54f9db4a09d8b + jest: ./bin/jest.js + checksum: 10c0/ae4fbee2756e03b6f99f612438e3b4e25789731599a4d4617ce5002d4c68f169f6223f6b21522fe65cd3d00519e0bb534ac6db6b2cdb7cd46a4ad3ded6542f38 languageName: node linkType: hard @@ -12958,6 +14044,18 @@ __metadata: languageName: node linkType: hard +"jszip@npm:^3.10.1": + version: 3.10.1 + resolution: "jszip@npm:3.10.1" + dependencies: + lie: "npm:~3.3.0" + pako: "npm:~1.0.2" + readable-stream: "npm:~2.3.6" + setimmediate: "npm:^1.0.5" + checksum: 10c0/58e01ec9c4960383fb8b38dd5f67b83ccc1ec215bf74c8a5b32f42b6e5fb79fada5176842a11409c4051b5b94275044851814a31076bf49e1be218d3ef57c863 + languageName: node + linkType: hard + "just-diff-apply@npm:^5.2.0": version: 5.5.0 resolution: "just-diff-apply@npm:5.5.0" @@ -13028,13 +14126,6 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^3.0.3": - version: 3.0.3 - resolution: "kleur@npm:3.0.3" - checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b - languageName: node - linkType: hard - "layerr@npm:^3.0.0": version: 3.0.0 resolution: "layerr@npm:3.0.0" @@ -13059,6 +14150,15 @@ __metadata: languageName: node linkType: hard +"lie@npm:~3.3.0": + version: 3.3.0 + resolution: "lie@npm:3.3.0" + dependencies: + immediate: "npm:~3.0.5" + checksum: 10c0/56dd113091978f82f9dc5081769c6f3b947852ecf9feccaf83e14a123bc630c2301439ce6182521e5fbafbde88e88ac38314327a4e0493a1bea7e0699a7af808 + languageName: node + linkType: hard + "lightningcss-darwin-arm64@npm:1.29.2": version: 1.29.2 resolution: "lightningcss-darwin-arm64@npm:1.29.2" @@ -13207,6 +14307,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: "npm:^6.0.0" + checksum: 10c0/139e8a7fe11cfbd7f20db03923cacfa5db9e14fa14887ea121345597472b4a63c1a42a8a5187defeeff6acf98fd568da7382aa39682d38f0af27433953a97751 + languageName: node + linkType: hard + "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -13235,6 +14344,19 @@ __metadata: languageName: node linkType: hard +"log4js@npm:^6.9.1": + version: 6.9.1 + resolution: "log4js@npm:6.9.1" + dependencies: + date-format: "npm:^4.0.14" + debug: "npm:^4.3.4" + flatted: "npm:^3.2.7" + rfdc: "npm:^1.3.0" + streamroller: "npm:^3.1.5" + checksum: 10c0/05846e48f72d662800c8189bd178c42b4aa2f0c574cfc90a1942cf90b76f621c44019e26796c8fd88da1b6f0fe8272cba607cbaad6ae6ede50a7a096b58197ea + languageName: node + linkType: hard + "longest-streak@npm:^3.0.0": version: 3.1.0 resolution: "longest-streak@npm:3.1.0" @@ -13311,6 +14433,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^11.0.0": + version: 11.1.0 + resolution: "lru-cache@npm:11.1.0" + checksum: 10c0/85c312f7113f65fae6a62de7985348649937eb34fb3d212811acbf6704dc322a421788aca253b62838f1f07049a84cc513d88f494e373d3756514ad263670a64 + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -13320,12 +14449,12 @@ __metadata: languageName: node linkType: hard -"lucide-react@npm:^0.503.0": - version: 0.503.0 - resolution: "lucide-react@npm:0.503.0" +"lucide-react@npm:^0.522.0": + version: 0.522.0 + resolution: "lucide-react@npm:0.522.0" peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/97d282acf1a384da690cd973804d11737ebdba744cd11b2a3807a06d407e0f1f975723d9ce4afcb55058e6bd179d77029272cddcc726232339a3fde263b375b4 + checksum: 10c0/92f18da5ade753c7955a3d0fe3779b62831bf1d6ab15396b6024ef66efe7df7b78e19728e3cf59d1bd01bbee16de0c474a5d6b2741e6b5c97d8374d02f776898 languageName: node linkType: hard @@ -13356,7 +14485,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.3.6": +"make-error@npm:^1.1.1, make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f @@ -14198,6 +15327,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.0.3": + version: 10.0.3 + resolution: "minimatch@npm:10.0.3" + dependencies: + "@isaacs/brace-expansion": "npm:^5.0.0" + checksum: 10c0/e43e4a905c5d70ac4cec8530ceaeccb9c544b1ba8ac45238e2a78121a01c17ff0c373346472d221872563204eabe929ad02669bb575cb1f0cc30facab369f70f + languageName: node + linkType: hard + "minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -14505,6 +15643,15 @@ __metadata: languageName: node linkType: hard +"napi-postinstall@npm:^0.2.4": + version: 0.2.5 + resolution: "napi-postinstall@npm:0.2.5" + bin: + napi-postinstall: lib/cli.js + checksum: 10c0/c4a1a8ca61aece10a6a7b46b834d7689321c4bb164710df9d896a273f24544084c5be95b47c55208036a06ae5bfa0afabb6a8886985d4438543ee07344b9c90c + languageName: node + linkType: hard + "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -15103,6 +16250,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: "npm:^1.0.0" + checksum: 10c0/a56af34a77f8df2ff61ddfb29431044557fcbcb7642d5a3233143ebba805fc7306ac1d448de724352861cb99de934bc9ab74f0d16fe6a5460bdbdf938de875ad + languageName: node + linkType: hard + "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -15121,6 +16277,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: "npm:^4.0.0" + checksum: 10c0/d72fa2f41adce59c198270aa4d3c832536c87a1806e0f69dffb7c1a7ca998fb053915ca833d90f166a8c082d3859eabfed95f01698a3214c20df6bb8de046312 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -15214,7 +16379,7 @@ __metadata: languageName: node linkType: hard -"pako@npm:~1.0.5": +"pako@npm:~1.0.2, pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe @@ -15363,6 +16528,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 10c0/b170f3060b31604cde93eefdb7392b89d832dfbc1bed717c9718cbe0f230c1669b7e75f87e19901da2250b84d092989a0f9e44d2ef41deb09aa3ad28e691a40a + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -15394,6 +16566,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^2.0.0": + version: 2.0.0 + resolution: "path-scurry@npm:2.0.0" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/3da4adedaa8e7ef8d6dc4f35a0ff8f05a9b4d8365f2b28047752b62d4c1ad73eec21e37b1579ef2d075920157856a3b52ae8309c480a6f1a8bbe06ff8e52b33c + languageName: node + linkType: hard + "path-type@npm:^1.0.0": version: 1.1.0 resolution: "path-type@npm:1.1.0" @@ -15512,6 +16694,13 @@ __metadata: languageName: node linkType: hard +"pirates@npm:^4.0.6, pirates@npm:^4.0.7": + version: 4.0.7 + resolution: "pirates@npm:4.0.7" + checksum: 10c0/a51f108dd811beb779d58a76864bbd49e239fa40c7984cd11596c75a121a8cc789f1c8971d8bb15f0dbf9d48b76c05bb62fcbce840f89b688c0fa64b37e8478a + languageName: node + linkType: hard + "pkg-dir@npm:^4.2.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" @@ -15530,6 +16719,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: "npm:^6.3.0" + checksum: 10c0/1afb23d2efb1ec9d8b2c4a0c37bf146822ad2774f074cb05b853be5dca1b40815c5960dd126df30ab8908349262a266f31b771e877235870a3b8fd313beebec5 + languageName: node + linkType: hard + "popper.js@npm:^1.16.0": version: 1.16.1 resolution: "popper.js@npm:1.16.1" @@ -15640,7 +16838,18 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": +"pretty-format@npm:30.0.2, pretty-format@npm:^30.0.0": + version: 30.0.2 + resolution: "pretty-format@npm:30.0.2" + dependencies: + "@jest/schemas": "npm:30.0.1" + ansi-styles: "npm:^5.2.0" + react-is: "npm:^18.3.1" + checksum: 10c0/cf542dc2d0be95e2b1c6e3a397a4fc13fce1c9f8feed6b56165c0d23c7a83423abb6b032ed8e3e1b7c1c0709f9b117dd30b5185f107e58f8766616be6de84850 + languageName: node + linkType: hard + +"pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" dependencies: @@ -15738,16 +16947,6 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1": - version: 2.4.2 - resolution: "prompts@npm:2.4.2" - dependencies: - kleur: "npm:^3.0.3" - sisteransi: "npm:^1.0.5" - checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 - languageName: node - linkType: hard - "prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" @@ -15843,10 +17042,10 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^6.0.0": - version: 6.1.0 - resolution: "pure-rand@npm:6.1.0" - checksum: 10c0/1abe217897bf74dcb3a0c9aba3555fe975023147b48db540aa2faf507aee91c03bf54f6aef0eb2bf59cc259a16d06b28eca37f0dc426d94f4692aeff02fb0e65 +"pure-rand@npm:^7.0.0": + version: 7.0.1 + resolution: "pure-rand@npm:7.0.1" + checksum: 10c0/9cade41030f5ec95f5d55a11a71404cd6f46b69becaad892097cd7f58e2c6248cd0a933349ca7d21336ab629f1da42ffe899699b671bc4651600eaf6e57f837e languageName: node linkType: hard @@ -16008,7 +17207,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0": +"react-is@npm:^18.0.0, react-is@npm:^18.3.1": version: 18.3.1 resolution: "react-is@npm:18.3.1" checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 @@ -16241,7 +17440,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.2, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.8": +"readable-stream@npm:^2.0.2, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -16703,6 +17902,13 @@ __metadata: languageName: node linkType: hard +"rfdc@npm:^1.3.0": + version: 1.4.1 + resolution: "rfdc@npm:1.4.1" + checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7 + languageName: node + linkType: hard + "rimraf@npm:^3.0.2": version: 3.0.2 resolution: "rimraf@npm:3.0.2" @@ -16725,6 +17931,18 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^6.0.1": + version: 6.0.1 + resolution: "rimraf@npm:6.0.1" + dependencies: + glob: "npm:^11.0.0" + package-json-from-dist: "npm:^1.0.0" + bin: + rimraf: dist/esm/bin.mjs + checksum: 10c0/b30b6b072771f0d1e73b4ca5f37bb2944ee09375be9db5f558fcd3310000d29dfcfa93cf7734d75295ad5a7486dc8e40f63089ced1722a664539ffc0c3ece8c6 + languageName: node + linkType: hard + "ripemd160@npm:=2.0.1": version: 2.0.1 resolution: "ripemd160@npm:2.0.1" @@ -17073,6 +18291,18 @@ __metadata: languageName: node linkType: hard +"selenium-webdriver@npm:^4.22.0": + version: 4.34.0 + resolution: "selenium-webdriver@npm:4.34.0" + dependencies: + "@bazel/runfiles": "npm:^6.3.1" + jszip: "npm:^3.10.1" + tmp: "npm:^0.2.3" + ws: "npm:^8.18.2" + checksum: 10c0/bfca387713677284d70b66aa419ad0e6f013945cca1f19bb780a62e4eff1f69190a165e939ef79e8f23af9aa0bd08b9a90c41ee6713eec30b7601034bd5f1824 + languageName: node + linkType: hard + "semver-compare@npm:^1.0.0": version: 1.0.0 resolution: "semver-compare@npm:1.0.0" @@ -17107,6 +18337,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + languageName: node + linkType: hard + "serialize-error@npm:^7.0.1": version: 7.0.1 resolution: "serialize-error@npm:7.0.1" @@ -17158,7 +18397,7 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.4": +"setimmediate@npm:^1.0.4, setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 @@ -17262,7 +18501,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1": +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 @@ -17297,13 +18536,6 @@ __metadata: languageName: node linkType: hard -"sisteransi@npm:^1.0.5": - version: 1.0.5 - resolution: "sisteransi@npm:1.0.5" - checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 - languageName: node - linkType: hard - "skin-tone@npm:^2.0.0": version: 2.0.0 resolution: "skin-tone@npm:2.0.0" @@ -17363,6 +18595,24 @@ __metadata: languageName: node linkType: hard +"sock-daemon@npm:^1.4.2": + version: 1.4.2 + resolution: "sock-daemon@npm:1.4.2" + dependencies: + rimraf: "npm:^5.0.5" + signal-exit: "npm:^4.1.0" + socket-post-message: "npm:^1.0.3" + checksum: 10c0/1b5e0b02fdd8cd5454fc7de80557c11aac5d88085d0cee80ead08b8f4df5e3c0a4b50ebb2ae2113dab94f36dc88b5d3b7d4b1c2c8e53bbcfbddfc741abf3bd00 + languageName: node + linkType: hard + +"socket-post-message@npm:^1.0.3": + version: 1.0.3 + resolution: "socket-post-message@npm:1.0.3" + checksum: 10c0/d3ffb51dad97754856aaa6709e036196f4b8b674f00366b71591ead122bcdbc073827f67d17c8b03c9a28c921b2c7cb277c581f6ca318d472034eae7afc169d1 + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.3": version: 8.0.5 resolution: "socks-proxy-agent@npm:8.0.5" @@ -17467,7 +18717,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": +"source-map@npm:^0.6.0, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 @@ -17584,7 +18834,7 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3": +"stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" dependencies: @@ -17639,7 +18889,18 @@ __metadata: languageName: node linkType: hard -"string-length@npm:^4.0.1": +"streamroller@npm:^3.1.5": + version: 3.1.5 + resolution: "streamroller@npm:3.1.5" + dependencies: + date-format: "npm:^4.0.14" + debug: "npm:^4.3.4" + fs-extra: "npm:^8.1.0" + checksum: 10c0/0bdeec34ad37487d959ba908f17067c938f544db88b5bb1669497a67a6b676413229ce5a6145c2812d06959ebeb8842e751076647d4b323ca06be612963b9099 + languageName: node + linkType: hard + +"string-length@npm:^4.0.1, string-length@npm:^4.0.2": version: 4.0.2 resolution: "string-length@npm:4.0.2" dependencies: @@ -17851,6 +19112,15 @@ __metadata: languageName: node linkType: hard +"synckit@npm:^0.11.8": + version: 0.11.8 + resolution: "synckit@npm:0.11.8" + dependencies: + "@pkgr/core": "npm:^0.2.4" + checksum: 10c0/a1de5131ee527512afcaafceb2399b2f3e63678e56b831e1cb2dc7019c972a8b654703a3b94ef4166868f87eb984ea252b467c9d9e486b018ec2e6a55c24dfd8 + languageName: node + linkType: hard + "tailwind-merge@npm:^3.2.0": version: 3.2.0 resolution: "tailwind-merge@npm:3.2.0" @@ -17941,6 +19211,21 @@ __metadata: languageName: node linkType: hard +"tests-e2-js@workspace:tests-e2e-js": + version: 0.0.0-use.local + resolution: "tests-e2-js@workspace:tests-e2e-js" + dependencies: + "@tauri-e2e/selenium": "npm:0.2.2" + "@types/node": "npm:^20.14.9" + "@types/selenium-webdriver": "npm:^4.1.28" + log4js: "npm:^6.9.1" + selenium-webdriver: "npm:^4.22.0" + ts-node: "npm:^10.9.2" + tsimp: "npm:^2.0.11" + typescript: "npm:^5.5.2" + languageName: unknown + linkType: soft + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -18047,6 +19332,13 @@ __metadata: languageName: node linkType: hard +"tmp@npm:^0.2.3": + version: 0.2.3 + resolution: "tmp@npm:0.2.3" + checksum: 10c0/3e809d9c2f46817475b452725c2aaa5d11985cf18d32a7a970ff25b568438e2c076c2e8609224feef3b7923fa9749b74428e3e634f6b8e520c534eef2fd24125 + languageName: node + linkType: hard + "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -18272,6 +19564,65 @@ __metadata: languageName: node linkType: hard +"ts-node@npm:^10.9.2": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" + dependencies: + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 + languageName: node + linkType: hard + +"tsimp@npm:^2.0.11": + version: 2.0.12 + resolution: "tsimp@npm:2.0.12" + dependencies: + "@isaacs/cached": "npm:^1.0.1" + "@isaacs/catcher": "npm:^1.0.4" + foreground-child: "npm:^3.1.1" + mkdirp: "npm:^3.0.1" + pirates: "npm:^4.0.6" + rimraf: "npm:^6.0.1" + signal-exit: "npm:^4.1.0" + sock-daemon: "npm:^1.4.2" + walk-up-path: "npm:^4.0.0" + peerDependencies: + typescript: ^5.1.0 + bin: + tsimp: dist/esm/bin.mjs + checksum: 10c0/c56c03a6a4df3ab5ebcefcc0b473992cbb7150173c331be6bda01670d5ae3965e65f30c42757cd391100a1c21485e167a05a350d875f41826b35c45008e5fac8 + languageName: node + linkType: hard + "tslib@npm:^1.11.1, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -18434,23 +19785,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.3.3, typescript@npm:~5.7.2": - version: 5.7.3 - resolution: "typescript@npm:5.7.3" +"typescript@npm:^5.5.2, typescript@npm:^5.8.3, typescript@npm:~5.8.3": + version: 5.8.3 + resolution: "typescript@npm:5.8.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa + checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48 languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin, typescript@patch:typescript@npm%3A~5.7.2#optional!builtin": - version: 5.7.3 - resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5786d5" +"typescript@patch:typescript@npm%3A^5.5.2#optional!builtin, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin, typescript@patch:typescript@npm%3A~5.8.3#optional!builtin": + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/6fd7e0ed3bf23a81246878c613423730c40e8bdbfec4c6e4d7bf1b847cbb39076e56ad5f50aa9d7ebd89877999abaee216002d3f2818885e41c907caaa192cc4 + checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb languageName: node linkType: hard @@ -18682,6 +20033,73 @@ __metadata: languageName: node linkType: hard +"unrs-resolver@npm:^1.7.11": + version: 1.9.2 + resolution: "unrs-resolver@npm:1.9.2" + dependencies: + "@unrs/resolver-binding-android-arm-eabi": "npm:1.9.2" + "@unrs/resolver-binding-android-arm64": "npm:1.9.2" + "@unrs/resolver-binding-darwin-arm64": "npm:1.9.2" + "@unrs/resolver-binding-darwin-x64": "npm:1.9.2" + "@unrs/resolver-binding-freebsd-x64": "npm:1.9.2" + "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.9.2" + "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.9.2" + "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.9.2" + "@unrs/resolver-binding-linux-arm64-musl": "npm:1.9.2" + "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.9.2" + "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.9.2" + "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.9.2" + "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.9.2" + "@unrs/resolver-binding-linux-x64-gnu": "npm:1.9.2" + "@unrs/resolver-binding-linux-x64-musl": "npm:1.9.2" + "@unrs/resolver-binding-wasm32-wasi": "npm:1.9.2" + "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.9.2" + "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.9.2" + "@unrs/resolver-binding-win32-x64-msvc": "npm:1.9.2" + napi-postinstall: "npm:^0.2.4" + dependenciesMeta: + "@unrs/resolver-binding-android-arm-eabi": + optional: true + "@unrs/resolver-binding-android-arm64": + optional: true + "@unrs/resolver-binding-darwin-arm64": + optional: true + "@unrs/resolver-binding-darwin-x64": + optional: true + "@unrs/resolver-binding-freebsd-x64": + optional: true + "@unrs/resolver-binding-linux-arm-gnueabihf": + optional: true + "@unrs/resolver-binding-linux-arm-musleabihf": + optional: true + "@unrs/resolver-binding-linux-arm64-gnu": + optional: true + "@unrs/resolver-binding-linux-arm64-musl": + optional: true + "@unrs/resolver-binding-linux-ppc64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-musl": + optional: true + "@unrs/resolver-binding-linux-s390x-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-musl": + optional: true + "@unrs/resolver-binding-wasm32-wasi": + optional: true + "@unrs/resolver-binding-win32-arm64-msvc": + optional: true + "@unrs/resolver-binding-win32-ia32-msvc": + optional: true + "@unrs/resolver-binding-win32-x64-msvc": + optional: true + checksum: 10c0/e3481cc19ea4b25f888e2412bbd80a729b13527a41b035e784b71d1a7d4e2109b58b174adce989085eb75c787435e80ffb385db2b1598288474f53beb01438c0 + languageName: node + linkType: hard + "unset-value@npm:^1.0.0": version: 1.0.0 resolution: "unset-value@npm:1.0.0" @@ -18919,6 +20337,13 @@ __metadata: languageName: node linkType: hard +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 + languageName: node + linkType: hard + "v8-to-istanbul@npm:^9.0.1": version: 9.3.0 resolution: "v8-to-istanbul@npm:9.3.0" @@ -19233,6 +20658,13 @@ __metadata: languageName: node linkType: hard +"walk-up-path@npm:^4.0.0": + version: 4.0.0 + resolution: "walk-up-path@npm:4.0.0" + checksum: 10c0/fabe344f91387d1d41df230af962ef18bf703dd4178006d55cd6412caacd187b54440002d4d53a982d4f7f0455567dcffb6d3884533c8b2268928eca3ebd8a19 + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -19447,7 +20879,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^5.0.0": +"write-file-atomic@npm:^5.0.0, write-file-atomic@npm:^5.0.1": version: 5.0.1 resolution: "write-file-atomic@npm:5.0.1" dependencies: @@ -19472,6 +20904,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.18.2": + version: 8.18.3 + resolution: "ws@npm:8.18.3" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 + languageName: node + linkType: hard + "xml-name-validator@npm:^4.0.0": version: 4.0.0 resolution: "xml-name-validator@npm:4.0.0" @@ -19521,7 +20968,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.3.1, yargs@npm:^17.7.2": +"yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -19546,6 +20993,13 @@ __metadata: languageName: node linkType: hard +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 10c0/0732468dd7622ed8a274f640f191f3eaf1f39d5349a1b72836df484998d7d9807fbea094e2f5486d6b0cd2414aad5775972df0e68f8604db89a239f0f4bf7443 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" @@ -19553,6 +21007,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.0.0": + version: 1.2.1 + resolution: "yocto-queue@npm:1.2.1" + checksum: 10c0/5762caa3d0b421f4bdb7a1926b2ae2189fc6e4a14469258f183600028eb16db3e9e0306f46e8ebf5a52ff4b81a881f22637afefbef5399d6ad440824e9b27f9f + languageName: node + linkType: hard + "zod@npm:^3.23.8": version: 3.24.2 resolution: "zod@npm:3.24.2"