mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-02 04:42:09 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38dce7e003 |
@@ -8,7 +8,6 @@ on:
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
- "rust-toolchain.toml"
|
||||
- ".cargo/config.toml"
|
||||
- ".github/workflows/lint-clippy.yml"
|
||||
workflow_dispatch:
|
||||
env:
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
name: Prepare Release
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [edited, closed]
|
||||
branches: [dev]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: Release channel
|
||||
required: true
|
||||
type: choice
|
||||
options: [rc, stable]
|
||||
default: rc
|
||||
release_tag:
|
||||
description: 'Optional tag: vX.Y.Z-rc[.N] for RC, vX.Y.Z for stable'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: prepare-release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
if: >-
|
||||
${{ github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.head.repo.full_name == github.repository &&
|
||||
github.event.pull_request.user.login == 'github-actions[bot]' &&
|
||||
((startsWith(github.event.pull_request.head.ref, 'release/v') &&
|
||||
((github.event.action == 'closed' && github.event.pull_request.merged == true) ||
|
||||
(github.event.changes.body && github.event.pull_request.state == 'open' &&
|
||||
contains(github.event.pull_request.body, '[x] Refresh this PR from latest dev')))) ||
|
||||
(startsWith(github.event.pull_request.head.ref, 'next-dev/v') &&
|
||||
github.event.changes.body && github.event.pull_request.state == 'open' &&
|
||||
(contains(github.event.pull_request.body, '[x] Refresh this PR from latest dev') ||
|
||||
contains(github.event.pull_request.body, '[x] Use the next minor version') !=
|
||||
contains(github.event.changes.body.from, '[x] Use the next minor version'))))) }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Require the dev branch
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
SOURCE_REF: ${{ github.ref }}
|
||||
run: |
|
||||
if [[ "$SOURCE_REF" != 'refs/heads/dev' ]]; then
|
||||
echo '::error::Run Prepare Release from the dev branch.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: '26.13.0'
|
||||
|
||||
- uses: pnpm/action-setup@v6
|
||||
if: github.event.action != 'closed'
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- run: pnpm install --frozen-lockfile --ignore-scripts
|
||||
if: github.event.action != 'closed'
|
||||
|
||||
- name: Create or refresh version or publication PR
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
RELEASE_CHANNEL: ${{ inputs.channel }}
|
||||
RELEASE_COMMAND: ${{ github.event.action == 'closed' && 'publish-pr' || startsWith(github.event.pull_request.head.ref, 'next-dev/') && 'next-dev' || 'prepare' }}
|
||||
run: node scripts-workflow/release.mjs "$RELEASE_COMMAND"
|
||||
+70
-117
@@ -1,9 +1,6 @@
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [edited]
|
||||
branches: [main]
|
||||
push:
|
||||
# -rc tag 时预览发布, 跳过 telegram 通知、跳过 winget 提交、跳过 latest.json 文件更新
|
||||
tags:
|
||||
@@ -14,59 +11,75 @@ env:
|
||||
RUST_BACKTRACE: short
|
||||
HUSKY: 0
|
||||
concurrency:
|
||||
group: release-publication
|
||||
cancel-in-progress: false
|
||||
group: '${{ github.workflow }} - ${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
prepare_release:
|
||||
name: Approve Snapshot and Prepare Draft Release
|
||||
if: >-
|
||||
${{ github.event_name == 'push' ||
|
||||
(github.event.changes.body &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository &&
|
||||
github.event.pull_request.user.login == 'github-actions[bot]' &&
|
||||
startsWith(github.event.pull_request.head.ref, 'publish/v') &&
|
||||
contains(github.event.pull_request.body, '[x] Publish this approved release')) }}
|
||||
check_tag_version:
|
||||
name: Check Release Tag and package.json Version Consistency
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: read
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
outputs:
|
||||
release_tag: ${{ steps.source.outputs.release_tag }}
|
||||
source_sha: ${{ steps.source.outputs.source_sha }}
|
||||
channel: ${{ steps.source.outputs.channel }}
|
||||
release_id: ${{ steps.draft.outputs.id }}
|
||||
steps:
|
||||
- name: Checkout trusted release tooling
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: '26.13.0'
|
||||
- name: Validate source and publish the approved snapshot
|
||||
id: source
|
||||
env:
|
||||
RELEASE_COMMAND: ${{ github.event_name == 'push' && 'validate-tag' || 'publish' }}
|
||||
run: node scripts-workflow/release.mjs "$RELEASE_COMMAND"
|
||||
|
||||
- name: Create or reuse draft release
|
||||
id: draft
|
||||
env:
|
||||
RELEASE_TAG: ${{ steps.source.outputs.release_tag }}
|
||||
SOURCE_SHA: ${{ steps.source.outputs.source_sha }}
|
||||
run: node scripts-workflow/release.mjs prepare-draft
|
||||
- name: Check if tag is from main branch
|
||||
run: |
|
||||
TAG_REF="${GITHUB_REF##*/}"
|
||||
echo "Checking if tag $TAG_REF is from main branch..."
|
||||
|
||||
TAG_COMMIT=$(git rev-list -n 1 $TAG_REF)
|
||||
MAIN_COMMITS=$(git rev-list origin/main)
|
||||
|
||||
if echo "$MAIN_COMMITS" | grep -q "$TAG_COMMIT"; then
|
||||
echo "✅ Tag $TAG_REF is from main branch"
|
||||
else
|
||||
echo "❌ Tag $TAG_REF is not from main branch"
|
||||
echo "This release workflow only accepts tags from main branch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check tag and package.json version
|
||||
run: |
|
||||
TAG_REF="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"
|
||||
echo "Current tag: $TAG_REF"
|
||||
|
||||
PKG_VERSION=$(jq -r .version package.json)
|
||||
echo "package.json version: $PKG_VERSION"
|
||||
|
||||
EXPECTED_TAG="v$PKG_VERSION"
|
||||
|
||||
if [[ "$TAG_REF" != "$EXPECTED_TAG" ]]; then
|
||||
echo "❌ Version mismatch:"
|
||||
echo " Git tag : $TAG_REF"
|
||||
echo " package.json : $EXPECTED_TAG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Tag and package.json version are consistent."
|
||||
|
||||
prepare_release:
|
||||
name: Prepare Draft Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check_tag_version]
|
||||
outputs:
|
||||
release_id: ${{ steps.prepare_release.outputs.id }}
|
||||
steps:
|
||||
- name: Create or update draft release
|
||||
id: prepare_release
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
name: 'Clash Verge Rev ${{ github.ref_name }}'
|
||||
body: 'Draft release, will be updated later.'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
draft: true
|
||||
prerelease: ${{ contains(github.ref_name, '-rc') }}
|
||||
|
||||
update_tag:
|
||||
name: Publish Completed Release
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
outputs:
|
||||
source_sha: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
channel: ${{ needs.prepare_release.outputs.channel }}
|
||||
name: Update tag
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
[
|
||||
@@ -78,8 +91,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
|
||||
- name: Group changelog platforms
|
||||
run: bash ./scripts-workflow/group_platforms.sh
|
||||
@@ -92,7 +103,7 @@ jobs:
|
||||
- name: Set Env
|
||||
run: |
|
||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||
TAG_REF="$RELEASE_TAG"
|
||||
TAG_REF="${GITHUB_REF##*/}"
|
||||
echo "TAG_NAME=$TAG_REF" >> $GITHUB_ENV
|
||||
VERSION=$(echo "$TAG_REF" | sed 's/^v//')
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
@@ -138,16 +149,10 @@ jobs:
|
||||
Created at ${{ env.BUILDTIME }}.
|
||||
EOF
|
||||
|
||||
- name: Verify release tag still points to the approved source
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SOURCE_SHA: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
run: node scripts-workflow/release.mjs verify-target
|
||||
|
||||
- name: Publish Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PRERELEASE: ${{ contains(env.RELEASE_TAG, '-rc') }}
|
||||
PRERELEASE: ${{ contains(github.ref_name, '-rc') }}
|
||||
run: |
|
||||
release_id="${{ needs.prepare_release.outputs.release_id }}"
|
||||
|
||||
@@ -176,8 +181,6 @@ jobs:
|
||||
release:
|
||||
name: Release Build
|
||||
needs: [prepare_release]
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -197,8 +200,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
@@ -248,6 +249,7 @@ jobs:
|
||||
echo "Rust target ${{ matrix.target }} installed."
|
||||
|
||||
- name: Tauri build
|
||||
# 上游 5.24 修改了 latest.json 的生成逻辑,且依赖 tauri-plugin-update 2.10.0 暂未发布,故锁定在 0.5.23 版本
|
||||
uses: tauri-apps/tauri-action@v1.0.0
|
||||
env:
|
||||
NODE_OPTIONS: '--max_old_space_size=4096'
|
||||
@@ -262,14 +264,11 @@ jobs:
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
releaseId: ${{ needs.prepare_release.outputs.release_id }}
|
||||
tagName: ${{ env.RELEASE_TAG }}
|
||||
tagName: ${{ github.ref_name }}
|
||||
releaseBody: 'Draft release, will be updated later.'
|
||||
releaseDraft: true
|
||||
prerelease: ${{ needs.prepare_release.outputs.channel == 'rc' }}
|
||||
releaseCommitish: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
tauriScript: pnpm
|
||||
args: --target ${{ matrix.target }}
|
||||
uploadUpdaterJson: ${{ needs.prepare_release.outputs.channel == 'stable' }}
|
||||
includeUpdaterJson: true
|
||||
|
||||
- name: Attest Windows bundles
|
||||
if: matrix.os == 'windows-latest'
|
||||
@@ -294,8 +293,6 @@ jobs:
|
||||
release-for-linux-arm:
|
||||
name: Release Build for Linux ARM
|
||||
needs: [prepare_release]
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -310,8 +307,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
@@ -425,7 +420,7 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release upload "$RELEASE_TAG" \
|
||||
gh release upload "${{ github.ref_name }}" \
|
||||
target/${{ matrix.target }}/release/bundle/deb/*.deb \
|
||||
target/${{ matrix.target }}/release/bundle/rpm/*.rpm \
|
||||
--clobber
|
||||
@@ -433,8 +428,6 @@ jobs:
|
||||
release-for-fixed-webview2:
|
||||
name: Release Build for Fixed WebView2
|
||||
needs: [prepare_release]
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -449,8 +442,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
@@ -541,50 +532,17 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$files = Get-ChildItem "target\${{ matrix.target }}\release\bundle\nsis\*setup*" | Select-Object -ExpandProperty FullName
|
||||
gh release upload "$env:RELEASE_TAG" $files --clobber
|
||||
gh release upload "${{ github.ref_name }}" $files --clobber
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
prepare-next-dev:
|
||||
name: Prepare Next Dev Version
|
||||
if: ${{ needs.update_tag.outputs.channel == 'stable' }}
|
||||
needs: [prepare_release, update_tag]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
concurrency:
|
||||
group: prepare-release
|
||||
cancel-in-progress: false
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
SOURCE_SHA: ${{ needs.prepare_release.outputs.source_sha }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: '26.13.0'
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
run_install: false
|
||||
- name: Prepare version and changelog PR
|
||||
run: |
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
node scripts-workflow/release.mjs next-dev
|
||||
|
||||
release-update:
|
||||
if: ${{ needs.update_tag.outputs.channel == 'stable' }}
|
||||
if: ${{ !contains(github.ref_name, '-rc') }}
|
||||
name: Release Update
|
||||
runs-on: ubuntu-latest
|
||||
needs: [update_tag]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.update_tag.outputs.source_sha }}
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v7
|
||||
@@ -605,14 +563,12 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-update-for-fixed-webview2:
|
||||
if: ${{ needs.update_tag.outputs.channel == 'stable' }}
|
||||
if: ${{ !contains(github.ref_name, '-rc') }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [update_tag]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.update_tag.outputs.source_sha }}
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v7
|
||||
@@ -633,7 +589,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
submit-to-winget:
|
||||
if: ${{ needs.update_tag.outputs.channel == 'stable' }}
|
||||
if: ${{ !contains(github.ref_name, '-rc') }}
|
||||
name: Submit to Winget
|
||||
runs-on: ubuntu-latest
|
||||
needs: [update_tag, release-update]
|
||||
@@ -641,7 +597,6 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.update_tag.outputs.source_sha }}
|
||||
fetch-depth: 0
|
||||
- name: Get Version
|
||||
run: |
|
||||
@@ -658,7 +613,7 @@ jobs:
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
|
||||
notify-telegram:
|
||||
if: ${{ needs.update_tag.outputs.channel == 'stable' }}
|
||||
if: ${{ !contains(github.ref_name, '-rc') }}
|
||||
name: Notify Telegram
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
@@ -671,8 +626,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.update_tag.outputs.source_sha }}
|
||||
|
||||
- name: Group changelog platforms
|
||||
run: bash ./scripts-workflow/group_platforms.sh
|
||||
|
||||
@@ -9,8 +9,6 @@ on:
|
||||
paths:
|
||||
- "src-tauri/**"
|
||||
- "**/*.rs"
|
||||
- "rustfmt.toml"
|
||||
- "rust-toolchain.toml"
|
||||
- ".github/workflows/rustfmt.yml"
|
||||
|
||||
permissions:
|
||||
|
||||
+6
-19
@@ -28,7 +28,7 @@ Before contributing, you need to set up your development environment. Follow the
|
||||
### Prerequisites
|
||||
|
||||
1. **Install Rust and Node.js**
|
||||
Follow the [Tauri prerequisites](https://tauri.app/start/prerequisites/) for your operating system. Use the Node.js version in [`.tool-versions`](.tool-versions); [`rust-toolchain.toml`](rust-toolchain.toml) selects the Rust version and required components when you run Cargo from this repository.
|
||||
Our project requires both Rust and Node.js. Follow the official installation instructions [here](https://tauri.app/start/prerequisites/).
|
||||
|
||||
### Windows Users
|
||||
|
||||
@@ -51,21 +51,18 @@ rustup set default-host x86_64-pc-windows-msvc
|
||||
|
||||
### Install Node.js Package Manager
|
||||
|
||||
[Corepack is no longer bundled with Node.js starting with Node.js 25](https://nodejs.org/api/corepack.html). Install it globally if it is not already available, then enable it:
|
||||
Enable `corepack`:
|
||||
|
||||
```bash
|
||||
npm install --global corepack
|
||||
corepack enable
|
||||
```
|
||||
|
||||
Run pnpm from this repository so Corepack selects the version pinned by `packageManager` in [`package.json`](package.json).
|
||||
|
||||
### Install Project Dependencies
|
||||
|
||||
Node.js dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm install
|
||||
```
|
||||
|
||||
Ubuntu-only system packages:
|
||||
@@ -81,24 +78,14 @@ pnpm run prebuild
|
||||
pnpm run prebuild --force # Re-download and overwrite Mihomo core and service binaries
|
||||
```
|
||||
|
||||
### Prepare the Development Service Source
|
||||
|
||||
`pnpm dev` builds the development service from a sibling checkout of [`clash-verge-service-ipc`](https://github.com/clash-verge-rev/clash-verge-service-ipc). The binaries downloaded by `pnpm prebuild` do not replace this source checkout.
|
||||
|
||||
Check the `clash_verge_service_ipc` dependency in [`src-tauri/Cargo.toml`](src-tauri/Cargo.toml), then clone the service repository alongside `clash-verge-rev` and check out the matching tag. If the sibling directory already exists, reuse it and check its version rather than overwriting it. Without this checkout, `pnpm dev` fails when it tries to access `../clash-verge-service-ipc/Cargo.toml`.
|
||||
|
||||
### Run the Development Server
|
||||
|
||||
Run these commands from the root of `clash-verge-rev`:
|
||||
|
||||
```bash
|
||||
pnpm dev # Build the development service and start the desktop app
|
||||
pnpm dev:diff # Alias of pnpm dev
|
||||
pnpm dev:tauri # Run Tauri directly with the tauri-dev feature
|
||||
pnpm dev # Standard
|
||||
pnpm dev:diff # If an app instance already exists
|
||||
pnpm dev:tauri # Run Tauri development mode
|
||||
```
|
||||
|
||||
For frontend-only development, use `pnpm web:dev`. It does not start the Rust backend or build the development service.
|
||||
|
||||
### Build the Project
|
||||
|
||||
Standard build:
|
||||
|
||||
Generated
+27
-26
@@ -1081,7 +1081,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "2.5.9-rc"
|
||||
version = "2.5.9"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
@@ -1334,7 +1334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2015,7 +2015,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2274,7 +2274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2790,7 +2790,7 @@ dependencies = [
|
||||
"gobject-sys 0.21.5",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3344,7 +3344,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.61.2",
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4215,7 +4215,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.20",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4382,7 +4382,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4859,7 +4859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5524,7 +5524,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6028,7 +6028,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6041,7 +6041,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6100,7 +6100,7 @@ dependencies = [
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6720,7 +6720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7069,9 +7069,9 @@ checksum = "c0e973b34477b7823833469eb0f5a3a60370fef7a453e02d751b59180d0a5a05"
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.37.2"
|
||||
version = "0.37.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5777b06fe6435126ae8d816eba269e050e1e10d302cf5461e9c49eccabc3548"
|
||||
checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"block2",
|
||||
@@ -7786,10 +7786,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.4",
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8455,7 +8455,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.20",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8564,7 +8564,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9106,7 +9106,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9127,7 +9127,7 @@ dependencies = [
|
||||
"objc2-foundation",
|
||||
"objc2-quartz-core",
|
||||
"raw-window-handle",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-version",
|
||||
]
|
||||
|
||||
@@ -9702,7 +9702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9743,11 +9743,11 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.57.1"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759c50ddad0ef9913bb5496cb9d509a50433a3b78cb0238d61105526589cf0e9"
|
||||
checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0"
|
||||
dependencies = [
|
||||
"base64 0.23.1",
|
||||
"base64 0.22.1",
|
||||
"block2",
|
||||
"cookie",
|
||||
"crossbeam-channel",
|
||||
@@ -9768,6 +9768,7 @@ dependencies = [
|
||||
"objc2-foundation",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"sha2 0.10.9",
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ tracing-estuary = { git = "https://github.com/Tunglies/tracing-estuary.git", bra
|
||||
tauri-plugin-clash-verge-sysinfo = { path = "crates/tauri-plugin-clash-verge-sysinfo" }
|
||||
tracing = "0.1.44"
|
||||
|
||||
tauri = { version = "2.12.4" }
|
||||
tauri = { version = "2.12.5" }
|
||||
tauri-plugin-clipboard-manager = "2.5.0"
|
||||
parking_lot = { version = "0.12.5", features = ["hardware-lock-elision"] }
|
||||
anyhow = "1.0.104"
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
## v2.5.9
|
||||
|
||||
- **Mihomo(Meta) 内核升级至 v1.19.33**
|
||||
|
||||
<details>
|
||||
<summary><strong> 🐞 修复问题 </strong></summary>
|
||||
|
||||
- 修复规则扩展包含空列表项时,「编辑规则」界面报错的问题
|
||||
- 修复 重启应用后定时自动备份不执行的问题
|
||||
- 修复托盘测速与代理页行为不一致的问题,移除托盘「测试延迟」入口
|
||||
- 修复通过 URL 导入订阅时,即使导入的订阅并非当前使用的订阅,也会重新加载当前配置
|
||||
- 修复 首页 网站测速失败后卡片一直显示测试中
|
||||
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
|
||||
- 修复 代理 在全局模式下无法展开节点组
|
||||
- 修复 自定义 CSS 无法修改编辑器字体和字号的问题
|
||||
- 修复 WebDAV 设置清空后无法保存
|
||||
|
||||
**🍎 macOS**
|
||||
|
||||
|
||||
@@ -129,7 +129,6 @@ export default defineConfig([
|
||||
'eslint.config.ts',
|
||||
`vite.config.mts`,
|
||||
'scripts/*.mjs',
|
||||
'scripts-workflow/*.mjs',
|
||||
'tests/*.ts',
|
||||
'src/polyfills/*.js',
|
||||
'tests/*.mjs',
|
||||
@@ -239,13 +238,6 @@ export default defineConfig([
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['scripts-workflow/*.mjs'],
|
||||
languageOptions: {
|
||||
globals: globals.node,
|
||||
},
|
||||
rules: { 'es-x/no-object-groupby': 'off' },
|
||||
},
|
||||
{
|
||||
files: ['scripts/perf/*.{mjs,mts}'],
|
||||
languageOptions: {
|
||||
|
||||
+7
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "2.5.9-rc",
|
||||
"version": "2.5.9",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"prepare": "husky || true",
|
||||
@@ -56,7 +56,7 @@
|
||||
"@tanstack/react-virtual": "^3.14.13",
|
||||
"@tauri-apps/api": "2.12.4",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.5.0",
|
||||
"@tauri-apps/plugin-dialog": "2.8.3",
|
||||
"@tauri-apps/plugin-dialog": "2.8.4",
|
||||
"@tauri-apps/plugin-fs": "2.7.1",
|
||||
"@tauri-apps/plugin-http": "2.8.3",
|
||||
"@tauri-apps/plugin-opener": "2.7.2",
|
||||
@@ -84,6 +84,7 @@
|
||||
"react-router": "^8.4.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"rehype-sanitize": "^6.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"swr": "^2.5.1",
|
||||
"tauri-plugin-mihomo-api": "github:clash-verge-rev/tauri-plugin-mihomo#main",
|
||||
"types-pac": "^1.0.3",
|
||||
@@ -94,7 +95,7 @@
|
||||
"@biomejs/biome": "^2.5.14",
|
||||
"@eslint-react/eslint-plugin": "^5.20.5",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tauri-apps/cli": "2.12.3",
|
||||
"@tauri-apps/cli": "2.12.4",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^26.0.0",
|
||||
"@types/react": "19.3.0",
|
||||
@@ -102,7 +103,7 @@
|
||||
"@types/validator": "^13.15.10",
|
||||
"@vitejs/plugin-legacy": "^8.2.3",
|
||||
"@vitejs/plugin-react": "^6.1.1",
|
||||
"@wdio/tauri-service": "1.5.0",
|
||||
"@wdio/tauri-service": "1.5.1",
|
||||
"adm-zip": "^0.6.1",
|
||||
"axios": "^1.20.0",
|
||||
"cli-color": "^2.0.4",
|
||||
@@ -122,7 +123,7 @@
|
||||
"https-proxy-agent": "^9.1.0",
|
||||
"husky": "^9.1.7",
|
||||
"jiti": "^2.7.0",
|
||||
"knip": "6.44.1",
|
||||
"knip": "6.43.0",
|
||||
"lint-staged": "^17.5.1",
|
||||
"sass": "^1.104.1",
|
||||
"tar": "^7.5.22",
|
||||
@@ -134,7 +135,7 @@
|
||||
"vite-plugin-svgr": "^5.2.0",
|
||||
"vitest": "^5.0.1",
|
||||
"webdriverio": "10.1.0",
|
||||
"ws": "8.22.1"
|
||||
"ws": "8.22.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,mjs}": [
|
||||
|
||||
Generated
+289
-88
@@ -206,8 +206,8 @@ importers:
|
||||
specifier: 2.5.0
|
||||
version: 2.5.0
|
||||
'@tauri-apps/plugin-dialog':
|
||||
specifier: 2.8.3
|
||||
version: 2.8.3
|
||||
specifier: 2.8.4
|
||||
version: 2.8.4
|
||||
'@tauri-apps/plugin-fs':
|
||||
specifier: 2.7.1
|
||||
version: 2.7.1
|
||||
@@ -289,6 +289,9 @@ importers:
|
||||
rehype-sanitize:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
remark-gfm:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1(supports-color@7.2.0)
|
||||
swr:
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1(react@19.3.1)
|
||||
@@ -315,8 +318,8 @@ importers:
|
||||
specifier: ^10.0.1
|
||||
version: 10.0.1(eslint@10.11.0(jiti@2.7.0)(supports-color@7.2.0))
|
||||
'@tauri-apps/cli':
|
||||
specifier: 2.12.3
|
||||
version: 2.12.3
|
||||
specifier: 2.12.4
|
||||
version: 2.12.4
|
||||
'@types/lodash-es':
|
||||
specifier: ^4.17.12
|
||||
version: 4.17.12
|
||||
@@ -339,8 +342,8 @@ importers:
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(vite@8.3.0(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.1)(terser@5.51.2)(yaml@2.9.1))
|
||||
'@wdio/tauri-service':
|
||||
specifier: 1.5.0
|
||||
version: 1.5.0(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
||||
specifier: 1.5.1
|
||||
version: 1.5.1(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
||||
adm-zip:
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1
|
||||
@@ -399,8 +402,8 @@ importers:
|
||||
specifier: ^2.7.0
|
||||
version: 2.7.0
|
||||
knip:
|
||||
specifier: 6.44.1
|
||||
version: 6.44.1
|
||||
specifier: 6.43.0
|
||||
version: 6.43.0
|
||||
lint-staged:
|
||||
specifier: ^17.5.1
|
||||
version: 17.5.1
|
||||
@@ -435,8 +438,8 @@ importers:
|
||||
specifier: 10.1.0
|
||||
version: 10.1.0(supports-color@7.2.0)(yauzl@2.10.0)
|
||||
ws:
|
||||
specifier: 8.22.1
|
||||
version: 8.22.1
|
||||
specifier: 8.22.0
|
||||
version: 8.22.0
|
||||
|
||||
packages:
|
||||
|
||||
@@ -2127,87 +2130,87 @@ packages:
|
||||
'@tauri-apps/api@2.12.4':
|
||||
resolution: {integrity: sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg==}
|
||||
|
||||
'@tauri-apps/cli-darwin-arm64@2.12.3':
|
||||
resolution: {integrity: sha512-xmVNoJOOKzKLj7GLHXmXLimRby9M42aBIJa0sB80N7o24eKV5JiVmToKTRLVH9yhL05GZ/B6rSSOmbzNFJwBAA==}
|
||||
'@tauri-apps/cli-darwin-arm64@2.12.4':
|
||||
resolution: {integrity: sha512-OxqKSckIkoJ6vX2AjifIJpTasFC0Hbdoo7gEiCmAjauABO3U8m2MRsLWe+QTiBwDx1mIrvgA+rvI7tvDnbnHVg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tauri-apps/cli-darwin-x64@2.12.3':
|
||||
resolution: {integrity: sha512-URd+0usfmUQQyb5kNPiKt2OT8gp7oGU7QR+qOppB6e35mpVBFFVNhWc9oWb3p0u71fDJ09DpF4T6m9xYxoIB8g==}
|
||||
'@tauri-apps/cli-darwin-x64@2.12.4':
|
||||
resolution: {integrity: sha512-fz76/77wMMJOaaUN6n3CybRG0P/MTEjjqYk81mGPyhi9m6Ue5T+LWBnJP/AkPooNatBPI2vtulGqomyMJ44lCQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.3':
|
||||
resolution: {integrity: sha512-0kwUVx2LbmOoTRlwF1oDww7th4/NSluv4ZBQ6KRZsFKg4g0TlTcIiJ0VehqkQYUeC9xIT1Mk6XtF52mI155VSQ==}
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.4':
|
||||
resolution: {integrity: sha512-K0w8Bof6Lt8QKLAYhRy0yy36ZH5iA/35VuSOvnxyjvCUZ+A3JKsUTlALviH/sVgAlisaPzzmeJSH8XOn4Q2HBA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.12.3':
|
||||
resolution: {integrity: sha512-gKSGDx6fx+HBLQmG6guChFdisbrCSdx9Yli+j5teOa64gm1CeM+C6NLru5Pj3ZkkEep05BmCFjxvX+cjqAycZQ==}
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.12.4':
|
||||
resolution: {integrity: sha512-j5rOnjmRUwWrm1oosf0zBYl4D+fqydgUROFCk0hvKZxvbTT8SOERes0QB7rBV/XWNy+kM6pCKzb3oSm2sRglzg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.12.3':
|
||||
resolution: {integrity: sha512-Yr59qMy/gcvAfBuFdCGlAmGiLsYWMFDbsP4bAI6iNBzcJTGrYWZGeiQhGDo29MQwfF/NUBqyM2qljXu5tZ6wjQ==}
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.12.4':
|
||||
resolution: {integrity: sha512-aOue3Fy6Jb7+oWcfAVUsVHfeTybSCt2CZoU06aO4jv4d2Ks/KnaTPwMAK3CLEduGOvBLY1lbBBrIyomqLLH5Sg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.12.3':
|
||||
resolution: {integrity: sha512-jKr0/REBMnLKC0OwPQZkyge0mKDaNZ0b/AbfGwVyCgFfwS730EVLfVDo3nt7MUu6jJaytRq08+xSj5qfy+U1+Q==}
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.12.4':
|
||||
resolution: {integrity: sha512-Fx6GShY/RvST+t6LMlTHAwd66+1tEaAAGrnU7cysVfaiRP1BKng5Vl6rVmO6rSLOA1Sp1dRzNYM4f0OWQGb7qA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.12.3':
|
||||
resolution: {integrity: sha512-gTkEqJAGCMROGanxHnzaJzQ+/rXl39HWVg0/hDODS1wDWBGqoceqGC6Qm1+mQbyT11xnsB8mKu/gyVID/YpFIw==}
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.12.4':
|
||||
resolution: {integrity: sha512-tNzZSa79Z1nRpHxEpQ38lsAFpKlFlYvoXzjTV+lRRn/zSf3wrdUC3wnLcq2XEadchPu4ttK0zivhYzr+XGD19Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-musl@2.12.3':
|
||||
resolution: {integrity: sha512-T2dTxL1svRym71fZtaW4pZYXbthbfFsEJr1NeOUg/p7laWXZbUt/8DMSZf8recu9f7+1F/Lv00HtzsEu6vDO9w==}
|
||||
'@tauri-apps/cli-linux-x64-musl@2.12.4':
|
||||
resolution: {integrity: sha512-jmZ1pr0xEqUhuEusWtt9Yt+GF6lCnGHUmIL+KIknpbjK/XQ2qkhDBhaxK/JMHM2A8dAacVXCxXJk2EXpwhQUfA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.12.3':
|
||||
resolution: {integrity: sha512-eoiQwpEZWbpsVHcM9BAzqqe4TCHszvr3rsM7pUQ4ofLK0lF1i1d/jX0Qo5DYMqcrUtwQuDdDuOCbcT0Izf1VwQ==}
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.12.4':
|
||||
resolution: {integrity: sha512-fGo8pgEHZxdSYgZ/J98m1usJ7NHKmKbq7k6uT0x1rpOq6Bg2YVzzpaAblWk710f5LHYBJIL5QIFS5IrD+4gmTg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.12.3':
|
||||
resolution: {integrity: sha512-kE+KUg6Dbbkgvcw0m99wJVIToFQzJqpMBAXah74WqxaLzssNwSTUccrHp6+QVzMhjQP330tvekFmnQF+0NbE6Q==}
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.12.4':
|
||||
resolution: {integrity: sha512-ezl8sQIcjYsye3TUnTH5VcWmWzccZASlQm7hlZt0dYyj1XD0qpVW47u2xYVrIKui0F8uQv/7QGZixdWiClBsbg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.12.3':
|
||||
resolution: {integrity: sha512-L7wndWAgX2mLW7alswpL3d1R0P9FN2WYBgHaQkAYEBxHHGkY4vFX9CjcRQ1LAxDAMIJxrY7/aDziFJeChS84NQ==}
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.12.4':
|
||||
resolution: {integrity: sha512-DJhDeCqjLDNMWYFy7ZS8cfeAHX2RK0RbQMLiA3bMVVkXRDJ4NBYiHriGqsUhsr9iG41aTb+dJGkFPmPw1gWwVw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli@2.12.3':
|
||||
resolution: {integrity: sha512-f7/LsY74SVb1ChmOPw1ajOpxii0GSzDAgmWHRci8JUYuuai04rXsSbFobpmB0sP2DdlvMD/B5ZotEn8GOGMRUg==}
|
||||
'@tauri-apps/cli@2.12.4':
|
||||
resolution: {integrity: sha512-JI9bHfudSRJikGOrjbXEm6RjzzvmKuLc+JixB1NE8hNzQkNlCCIC3pTES3uypkR9lxHrsbxzcnSwhI2IxBQphw==}
|
||||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
|
||||
'@tauri-apps/plugin-clipboard-manager@2.5.0':
|
||||
resolution: {integrity: sha512-dibUy1nKURYDXRMvjNk4deAbTZ5jPQ8wCE4nolt5xniryWgXQ4sK2GkFXoXlHbRdPzfZptZj95BRLfalA7m/2Q==}
|
||||
|
||||
'@tauri-apps/plugin-dialog@2.8.3':
|
||||
resolution: {integrity: sha512-Hd/yBfk2R5v2MFrz/0VArSXeh8xKLLXGunqSiTtcHKn1zNZwaKujuA0VSwUvNfwC4hDoF1PveS+gBDNe3nHspw==}
|
||||
'@tauri-apps/plugin-dialog@2.8.4':
|
||||
resolution: {integrity: sha512-+6ZOiXenOaxXwb8qCbBPdT2jX2cFPaVVHGIskrpmJLpmWj+qKRTD6X/z9x7hTdSQn7NedcoXCkWGej4a7dC4lw==}
|
||||
|
||||
'@tauri-apps/plugin-fs@2.7.1':
|
||||
resolution: {integrity: sha512-4TBVjpi/q8PuNzjpkAc2iBGXMTLjOrAyfTiiOL8ORaJCZJRG3tjzmQ4sqs2CMG75FvLyRkOkERfP7AyY4iBNwQ==}
|
||||
@@ -2623,20 +2626,20 @@ packages:
|
||||
resolution: {integrity: sha512-0ZAEIo6PNyMIJPlOGkIgyOJUjcd0pC8/QHlVAAe1c91/IcjZ1X+k0yidXHaboJdN7dq1XPUacmhRdtua0U5EZg==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/native-core@1.3.0':
|
||||
resolution: {integrity: sha512-wUwc0QTdvhD0LwH4YcRaN9JWLX/yac8sovddUR5/4sqHMNJr3yaN11bpIfYoD/bEk+1nTLjWuDCFpe5l5wUgLQ==}
|
||||
'@wdio/native-core@1.3.1':
|
||||
resolution: {integrity: sha512-fdGk2lEr2vS+bClJXuZEnsG30cLzQv+B9W+dAt/Yte/fE33s/vDBn7hHwFx8aZLTOS0pPExErUxYiZEMXX+04g==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/native-spy@1.4.0':
|
||||
resolution: {integrity: sha512-unsC2Vgu5T9atD478Zj/p2N+rVSK4i/NibIaaEw4rZF/T5u5bmAHChFntEiBEfyMzd62VwbhKhzwwOSKjzrfJA==}
|
||||
'@wdio/native-spy@1.4.1':
|
||||
resolution: {integrity: sha512-KGOmgaicHqDkqj+s2bxXsRsb27IzW6carlyTu1xcrJI34yUbC0v14F8mbhuZcewW+mt2xhmC17yITwAbNa8PKw==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/native-types@2.6.0':
|
||||
resolution: {integrity: sha512-MVMVpZTH+UY6nUtLClCzY4BQSIs/nCCHo81i4ClLR+b2NehyBvwccttXDAGPgf0icyHUhd+PgIPXaLgRcm4M9A==}
|
||||
'@wdio/native-types@2.6.1':
|
||||
resolution: {integrity: sha512-Rm5chX+MrRhVgJYcYdcX/yyTZaLjxvi0w/fnSgPaDT16gMIntXlk22K2x3hwEdaUonOKepZyhh4jr9ZgRz7UaQ==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/native-utils@2.8.0':
|
||||
resolution: {integrity: sha512-TmIkPAd19FkJ747AdFVEtawbakVV3HHCh8zk3Kl/FLc6B2bbea7hn90jtLxqBZgCVqUuJIBcMNFg/nV/hgBFOw==}
|
||||
'@wdio/native-utils@2.8.1':
|
||||
resolution: {integrity: sha512-QbmZjGkLUC2bmUJSzyqsHM11HND1D7tkxHFssUV1Kmx43+oPAeHHVR0NSZu2hMzSNrDZMBAmNYycR+3X8rqWcA==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
peerDependencies:
|
||||
tsx: ^4.22.4
|
||||
@@ -2660,8 +2663,8 @@ packages:
|
||||
resolution: {integrity: sha512-lNLLPUk4y1Yp5pWwBFF+tjZIy7bOv0TPTk4HDWV4LnnHnkc24abI0nN+kb2y5/JV8ZgwLCCVKUFRdRUxfKsAaQ==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/tauri-service@1.5.0':
|
||||
resolution: {integrity: sha512-S3fs8T+jgNOFi4x/X2z69unS/1K3ZB28+owBouhHtVnrMKeBWAKP46IHnp8c8AZXppn6fiPNC4M1jfRZbLKeKw==}
|
||||
'@wdio/tauri-service@1.5.1':
|
||||
resolution: {integrity: sha512-nfzJU2x7bxvIXtYo+yvrX4Xwuba8h5hXOlJ0IyHanGg0ELavY/2UfyxygJDTcSGO+pCQMdC9JJEyMvaS50AtZQ==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
peerDependencies:
|
||||
webdriverio: ^9.0.0
|
||||
@@ -3238,6 +3241,10 @@ packages:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
escape-string-regexp@5.0.0:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
eslint-import-context@0.1.9:
|
||||
resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==}
|
||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||
@@ -3861,8 +3868,8 @@ packages:
|
||||
keyv@5.6.0:
|
||||
resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==}
|
||||
|
||||
knip@6.44.1:
|
||||
resolution: {integrity: sha512-Hbd8nvkIsNgFfXgC7Jsb5LHv7jj6VwA3tmfHd53XPX2z9Vc9RnAZqV0BIiP4OrtYqKwCoLseFHQZerb1bNlbSw==}
|
||||
knip@6.43.0:
|
||||
resolution: {integrity: sha512-8l3cCOg/EXoILO0qcSoMra49yQM91+lEIR4fu5Ko8rrArGX8xKdKZiGI9psPiY6rhLmfLERcMfFEByF0wli5CA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
@@ -4011,6 +4018,9 @@ packages:
|
||||
magic-string@1.4.1:
|
||||
resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==}
|
||||
|
||||
markdown-table@3.0.4:
|
||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||
|
||||
marked@14.0.0:
|
||||
resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -4020,9 +4030,30 @@ packages:
|
||||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
mdast-util-find-and-replace@3.0.2:
|
||||
resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
|
||||
|
||||
mdast-util-from-markdown@2.0.3:
|
||||
resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==}
|
||||
|
||||
mdast-util-gfm-autolink-literal@2.0.1:
|
||||
resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
|
||||
|
||||
mdast-util-gfm-footnote@2.1.0:
|
||||
resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
|
||||
|
||||
mdast-util-gfm-strikethrough@2.0.0:
|
||||
resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
|
||||
|
||||
mdast-util-gfm-table@2.0.0:
|
||||
resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
|
||||
|
||||
mdast-util-gfm-task-list-item@2.0.0:
|
||||
resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
|
||||
|
||||
mdast-util-gfm@3.1.0:
|
||||
resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
|
||||
|
||||
mdast-util-mdx-expression@2.0.1:
|
||||
resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
|
||||
|
||||
@@ -4059,6 +4090,27 @@ packages:
|
||||
micromark-core-commonmark@2.0.3:
|
||||
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
|
||||
|
||||
micromark-extension-gfm-autolink-literal@2.1.0:
|
||||
resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
|
||||
|
||||
micromark-extension-gfm-footnote@2.1.0:
|
||||
resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
|
||||
|
||||
micromark-extension-gfm-strikethrough@2.1.0:
|
||||
resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
|
||||
|
||||
micromark-extension-gfm-table@2.1.2:
|
||||
resolution: {integrity: sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==}
|
||||
|
||||
micromark-extension-gfm-tagfilter@2.0.0:
|
||||
resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
|
||||
|
||||
micromark-extension-gfm-task-list-item@2.1.0:
|
||||
resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
|
||||
|
||||
micromark-extension-gfm@3.0.0:
|
||||
resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
|
||||
|
||||
micromark-factory-destination@2.0.1:
|
||||
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
|
||||
|
||||
@@ -4499,12 +4551,18 @@ packages:
|
||||
rehype-sanitize@6.0.0:
|
||||
resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==}
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
|
||||
|
||||
remark-parse@11.0.0:
|
||||
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
|
||||
|
||||
remark-rehype@11.1.2:
|
||||
resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
|
||||
|
||||
remark-stringify@11.0.0:
|
||||
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
|
||||
|
||||
resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
|
||||
@@ -5074,8 +5132,8 @@ packages:
|
||||
resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
ws@8.22.1:
|
||||
resolution: {integrity: sha512-oyL6OPYme/CmiFvNuGzeoxCJ4nOrZE2O1FwM9MWM1AsGri6nLXB2pg+lNA8aLeXMSav0J6eIVS1j6vUPzUtK9g==}
|
||||
ws@8.22.0:
|
||||
resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
@@ -6824,58 +6882,58 @@ snapshots:
|
||||
|
||||
'@tauri-apps/api@2.12.4': {}
|
||||
|
||||
'@tauri-apps/cli-darwin-arm64@2.12.3':
|
||||
'@tauri-apps/cli-darwin-arm64@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-darwin-x64@2.12.3':
|
||||
'@tauri-apps/cli-darwin-x64@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.3':
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.12.3':
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.12.3':
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.12.3':
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.12.3':
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-x64-musl@2.12.3':
|
||||
'@tauri-apps/cli-linux-x64-musl@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.12.3':
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.12.3':
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.12.3':
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.12.4':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli@2.12.3':
|
||||
'@tauri-apps/cli@2.12.4':
|
||||
optionalDependencies:
|
||||
'@tauri-apps/cli-darwin-arm64': 2.12.3
|
||||
'@tauri-apps/cli-darwin-x64': 2.12.3
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf': 2.12.3
|
||||
'@tauri-apps/cli-linux-arm64-gnu': 2.12.3
|
||||
'@tauri-apps/cli-linux-arm64-musl': 2.12.3
|
||||
'@tauri-apps/cli-linux-riscv64-gnu': 2.12.3
|
||||
'@tauri-apps/cli-linux-x64-gnu': 2.12.3
|
||||
'@tauri-apps/cli-linux-x64-musl': 2.12.3
|
||||
'@tauri-apps/cli-win32-arm64-msvc': 2.12.3
|
||||
'@tauri-apps/cli-win32-ia32-msvc': 2.12.3
|
||||
'@tauri-apps/cli-win32-x64-msvc': 2.12.3
|
||||
'@tauri-apps/cli-darwin-arm64': 2.12.4
|
||||
'@tauri-apps/cli-darwin-x64': 2.12.4
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf': 2.12.4
|
||||
'@tauri-apps/cli-linux-arm64-gnu': 2.12.4
|
||||
'@tauri-apps/cli-linux-arm64-musl': 2.12.4
|
||||
'@tauri-apps/cli-linux-riscv64-gnu': 2.12.4
|
||||
'@tauri-apps/cli-linux-x64-gnu': 2.12.4
|
||||
'@tauri-apps/cli-linux-x64-musl': 2.12.4
|
||||
'@tauri-apps/cli-win32-arm64-msvc': 2.12.4
|
||||
'@tauri-apps/cli-win32-ia32-msvc': 2.12.4
|
||||
'@tauri-apps/cli-win32-x64-msvc': 2.12.4
|
||||
|
||||
'@tauri-apps/plugin-clipboard-manager@2.5.0':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.12.4
|
||||
|
||||
'@tauri-apps/plugin-dialog@2.8.3':
|
||||
'@tauri-apps/plugin-dialog@2.8.4':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.12.4
|
||||
|
||||
@@ -7275,11 +7333,11 @@ snapshots:
|
||||
safe-regex2: 5.1.1
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
'@wdio/native-core@1.3.0(supports-color@7.2.0)':
|
||||
'@wdio/native-core@1.3.1(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@wdio/logger': 9.29.1
|
||||
'@wdio/native-types': 2.6.0
|
||||
'@wdio/native-utils': 2.8.0(supports-color@7.2.0)
|
||||
'@wdio/native-types': 2.6.1
|
||||
'@wdio/native-utils': 2.8.1(supports-color@7.2.0)
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
get-port: 7.2.0
|
||||
tslib: 2.8.1
|
||||
@@ -7287,11 +7345,11 @@ snapshots:
|
||||
- supports-color
|
||||
- tsx
|
||||
|
||||
'@wdio/native-spy@1.4.0': {}
|
||||
'@wdio/native-spy@1.4.1': {}
|
||||
|
||||
'@wdio/native-types@2.6.0': {}
|
||||
'@wdio/native-types@2.6.1': {}
|
||||
|
||||
'@wdio/native-utils@2.8.0(supports-color@7.2.0)':
|
||||
'@wdio/native-utils@2.8.1(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@wdio/logger': 9.29.1
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
@@ -7325,14 +7383,14 @@ snapshots:
|
||||
easy-table: 1.2.0
|
||||
pretty-ms: 9.3.1
|
||||
|
||||
'@wdio/tauri-service@1.5.0(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))':
|
||||
'@wdio/tauri-service@1.5.1(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))':
|
||||
dependencies:
|
||||
'@wdio/globals': 9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
||||
'@wdio/logger': 9.29.1
|
||||
'@wdio/native-core': 1.3.0(supports-color@7.2.0)
|
||||
'@wdio/native-spy': 1.4.0
|
||||
'@wdio/native-types': 2.6.0
|
||||
'@wdio/native-utils': 2.8.0(supports-color@7.2.0)
|
||||
'@wdio/native-core': 1.3.1(supports-color@7.2.0)
|
||||
'@wdio/native-spy': 1.4.1
|
||||
'@wdio/native-types': 2.6.1
|
||||
'@wdio/native-utils': 2.8.1(supports-color@7.2.0)
|
||||
'@wdio/spec-reporter': 9.31.2
|
||||
'@wdio/types': 9.31.2
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
@@ -7948,6 +8006,8 @@ snapshots:
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
escape-string-regexp@5.0.0: {}
|
||||
|
||||
eslint-import-context@0.1.9(unrs-resolver@1.12.2):
|
||||
dependencies:
|
||||
get-tsconfig: 4.14.3
|
||||
@@ -8701,7 +8761,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@keyv/serialize': 1.1.1
|
||||
|
||||
knip@6.44.1:
|
||||
knip@6.43.0:
|
||||
dependencies:
|
||||
formatly: 0.11.4
|
||||
get-tsconfig: 4.14.3
|
||||
@@ -8838,10 +8898,19 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
|
||||
markdown-table@3.0.4: {}
|
||||
|
||||
marked@14.0.0: {}
|
||||
|
||||
math-intrinsics@1.1.0: {}
|
||||
|
||||
mdast-util-find-and-replace@3.0.2:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
escape-string-regexp: 5.0.0
|
||||
unist-util-is: 6.0.1
|
||||
unist-util-visit-parents: 6.0.2
|
||||
|
||||
mdast-util-from-markdown@2.0.3(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -8859,6 +8928,63 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-autolink-literal@2.0.1:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
ccount: 2.0.1
|
||||
devlop: 1.1.0
|
||||
mdast-util-find-and-replace: 3.0.2
|
||||
micromark-util-character: 2.1.1
|
||||
|
||||
mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
micromark-util-normalize-identifier: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-table@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
markdown-table: 3.0.4
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm@3.1.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-gfm-autolink-literal: 2.0.1
|
||||
mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-table: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-mdx-expression@2.0.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
@@ -8965,6 +9091,64 @@ snapshots:
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-autolink-literal@2.1.0:
|
||||
dependencies:
|
||||
micromark-util-character: 2.1.1
|
||||
micromark-util-sanitize-uri: 2.0.1
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-footnote@2.1.0:
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
micromark-core-commonmark: 2.0.3
|
||||
micromark-factory-space: 2.0.1
|
||||
micromark-util-character: 2.1.1
|
||||
micromark-util-normalize-identifier: 2.0.1
|
||||
micromark-util-sanitize-uri: 2.0.1
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-strikethrough@2.1.0:
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
micromark-util-chunked: 2.0.1
|
||||
micromark-util-classify-character: 2.0.1
|
||||
micromark-util-resolve-all: 2.0.1
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-table@2.1.2:
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
micromark-factory-space: 2.0.1
|
||||
micromark-util-character: 2.1.1
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-tagfilter@2.0.0:
|
||||
dependencies:
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm-task-list-item@2.1.0:
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
micromark-factory-space: 2.0.1
|
||||
micromark-util-character: 2.1.1
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-gfm@3.0.0:
|
||||
dependencies:
|
||||
micromark-extension-gfm-autolink-literal: 2.1.0
|
||||
micromark-extension-gfm-footnote: 2.1.0
|
||||
micromark-extension-gfm-strikethrough: 2.1.0
|
||||
micromark-extension-gfm-table: 2.1.2
|
||||
micromark-extension-gfm-tagfilter: 2.0.0
|
||||
micromark-extension-gfm-task-list-item: 2.1.0
|
||||
micromark-util-combine-extensions: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-factory-destination@2.0.1:
|
||||
dependencies:
|
||||
micromark-util-character: 2.1.1
|
||||
@@ -9490,6 +9674,17 @@ snapshots:
|
||||
'@types/hast': 3.0.5
|
||||
hast-util-sanitize: 5.0.2
|
||||
|
||||
remark-gfm@4.0.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-gfm: 3.1.0(supports-color@7.2.0)
|
||||
micromark-extension-gfm: 3.0.0
|
||||
remark-parse: 11.0.0(supports-color@7.2.0)
|
||||
remark-stringify: 11.0.0
|
||||
unified: 11.0.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-parse@11.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -9507,6 +9702,12 @@ snapshots:
|
||||
unified: 11.0.5
|
||||
vfile: 6.0.3
|
||||
|
||||
remark-stringify@11.0.0:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
unified: 11.0.5
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
@@ -10023,7 +10224,7 @@ snapshots:
|
||||
deepmerge-ts: 8.0.2
|
||||
https-proxy-agent: 9.1.0(supports-color@7.2.0)
|
||||
undici: 8.11.2
|
||||
ws: 8.22.1
|
||||
ws: 8.22.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- kerberos
|
||||
@@ -10091,7 +10292,7 @@ snapshots:
|
||||
string-width: 7.2.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
ws@8.22.1: {}
|
||||
ws@8.22.0: {}
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
|
||||
@@ -1,761 +0,0 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { appendFileSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
|
||||
const env = process.env
|
||||
const repository = env.GITHUB_REPOSITORY
|
||||
const refreshLabel = 'Refresh this PR from latest dev'
|
||||
const publishLabel = 'Publish this approved release'
|
||||
const minorLabel = 'Use the next minor version'
|
||||
const checked = (body, label = refreshLabel) =>
|
||||
(body || '')
|
||||
.split('\n')
|
||||
.some((line) => line.toLowerCase() === `- [x] ${label}`.toLowerCase())
|
||||
const versionPattern = '(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)'
|
||||
const rcPattern = new RegExp(`^v${versionPattern}-rc(?:\\.(0|[1-9][0-9]*))?$`)
|
||||
const stablePattern = new RegExp(`^v${versionPattern}$`)
|
||||
const versionFiles = [
|
||||
'package.json',
|
||||
'src-tauri/tauri.conf.json',
|
||||
'src-tauri/Cargo.toml',
|
||||
'Cargo.lock',
|
||||
]
|
||||
const read = (path) => readFileSync(path, 'utf8')
|
||||
const json = (path) => JSON.parse(read(path))
|
||||
const run = (command, args, options = {}) =>
|
||||
execFileSync(command, args, { encoding: 'utf8', ...options }).trim()
|
||||
const git = (...args) => run('git', args)
|
||||
const gitFile = (sha, path) =>
|
||||
execFileSync('git', ['show', `${sha}:${path}`], { encoding: 'utf8' })
|
||||
const isRc = (tag) => tag.match(rcPattern)?.[0] === tag
|
||||
const isRelease = (tag) => isRc(tag) || stablePattern.test(tag)
|
||||
const titleFor = (tag) => `${isRc(tag) ? 'Pre-Release' : 'Release'}: ${tag}`
|
||||
const branchTag = (branch, prefix = 'release/') =>
|
||||
branch.startsWith(prefix) && isRelease(branch.slice(prefix.length))
|
||||
? branch.slice(prefix.length)
|
||||
: undefined
|
||||
const latest = (tags) =>
|
||||
tags.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })).at(-1)
|
||||
const summary = (text) => appendFileSync(env.GITHUB_STEP_SUMMARY, `${text}\n`)
|
||||
const endpoint = (path) =>
|
||||
path === 'graphql' ? path : `repos/${repository}/${path}`
|
||||
const list = (path) =>
|
||||
JSON.parse(run('gh', ['api', '--paginate', '--slurp', endpoint(path)])).flat()
|
||||
|
||||
function api(path, body, method = 'POST') {
|
||||
const response = run(
|
||||
'gh',
|
||||
['api', '--method', method, endpoint(path), '--input', '-'],
|
||||
{
|
||||
input: JSON.stringify(body),
|
||||
},
|
||||
)
|
||||
const result = response ? JSON.parse(response) : null
|
||||
if (result?.errors) throw new Error(JSON.stringify(result.errors))
|
||||
return result
|
||||
}
|
||||
|
||||
const get = (path) => JSON.parse(run('gh', ['api', endpoint(path)]))
|
||||
const canWrite = (login) =>
|
||||
['write', 'maintain', 'admin'].includes(
|
||||
get(`collaborators/${login}/permission`).permission,
|
||||
)
|
||||
|
||||
function output(values) {
|
||||
appendFileSync(
|
||||
env.GITHUB_OUTPUT,
|
||||
Object.entries(values)
|
||||
.map(([key, value]) => `${key}=${value}\n`)
|
||||
.join(''),
|
||||
)
|
||||
}
|
||||
|
||||
function versionPatternFor(path) {
|
||||
if (path.endsWith('.json')) return /("version"\s*:\s*")[^"]+/
|
||||
return path === 'Cargo.lock'
|
||||
? /(\[\[package\]\]\r?\nname = "clash-verge"\r?\nversion = ")[^"]+/
|
||||
: /(^version\s*=\s*")[^"]+/m
|
||||
}
|
||||
|
||||
function validateVersions(tag, sha) {
|
||||
for (const path of versionFiles) {
|
||||
const content = sha ? gitFile(sha, path) : read(path)
|
||||
const version = path.endsWith('.json')
|
||||
? JSON.parse(content).version
|
||||
: content.match(versionPatternFor(path))?.[0].split('"').at(-1)
|
||||
if (`v${version}` !== tag)
|
||||
throw new Error(`${path} version does not match ${tag}.`)
|
||||
}
|
||||
}
|
||||
|
||||
function validateVersionCommit(tag, sha) {
|
||||
validateVersions(tag, sha)
|
||||
const commit = get(`commits/${sha}`)
|
||||
if (!commit.commit.verification.verified || commit.parents.length !== 1)
|
||||
throw new Error('The version commit must be signed and have one parent.')
|
||||
const title = commit.commit.message.split('\n')[0]
|
||||
if (title.replace(/ \(#\d+\)$/, '') !== titleFor(tag))
|
||||
throw new Error('The final version commit has an unexpected title.')
|
||||
const parent = commit.parents[0].sha
|
||||
const changed = git('diff', '--name-only', parent, sha)
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
if (
|
||||
changed.some((path) => !versionFiles.includes(path)) ||
|
||||
git('diff', '--summary', parent, sha)
|
||||
)
|
||||
throw new Error(
|
||||
'The version commit changes files outside the four version files.',
|
||||
)
|
||||
for (const path of versionFiles) {
|
||||
const before = gitFile(parent, path)
|
||||
const after = gitFile(sha, path)
|
||||
if (
|
||||
before.replace(versionPatternFor(path), '$1VERSION') !==
|
||||
after.replace(versionPatternFor(path), '$1VERSION')
|
||||
)
|
||||
throw new Error(`${path} contains changes other than its version.`)
|
||||
}
|
||||
}
|
||||
|
||||
function remoteRefs() {
|
||||
return git('ls-remote', '--heads', '--tags', '--refs', 'origin')
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map((line) => line.split('\t'))
|
||||
}
|
||||
|
||||
function fetchBranches() {
|
||||
git(
|
||||
'fetch',
|
||||
'--no-tags',
|
||||
'origin',
|
||||
'+refs/heads/dev:refs/remotes/origin/dev',
|
||||
'+refs/heads/main:refs/remotes/origin/main',
|
||||
)
|
||||
}
|
||||
|
||||
function prepare() {
|
||||
let refresh
|
||||
if (env.GITHUB_EVENT_NAME === 'pull_request_target') {
|
||||
const event = json(env.GITHUB_EVENT_PATH)
|
||||
if (checked(event.changes?.body?.from) || !checked(event.pull_request.body))
|
||||
return
|
||||
if (!canWrite(event.sender.login))
|
||||
throw new Error('Refreshing a version PR requires write access.')
|
||||
refresh = get(`pulls/${event.pull_request.number}`)
|
||||
if (refresh.state !== 'open' || !checked(refresh.body)) return
|
||||
requireBotPr(refresh, 'dev', 'release/')
|
||||
}
|
||||
fetchBranches()
|
||||
git('checkout', '--detach', 'origin/dev')
|
||||
const channel = refresh
|
||||
? isRc(branchTag(refresh.head.ref))
|
||||
? 'rc'
|
||||
: 'stable'
|
||||
: env.RELEASE_CHANNEL || 'rc'
|
||||
if (!['rc', 'stable'].includes(channel))
|
||||
throw new Error('Unknown release channel.')
|
||||
const requested = refresh
|
||||
? branchTag(refresh.head.ref)
|
||||
: env.RELEASE_TAG || ''
|
||||
if (
|
||||
requested &&
|
||||
!(channel === 'rc' ? isRc(requested) : stablePattern.test(requested))
|
||||
)
|
||||
throw new Error(
|
||||
channel === 'rc'
|
||||
? 'Expected vX.Y.Z-rc or vX.Y.Z-rc.N.'
|
||||
: 'Expected vX.Y.Z.',
|
||||
)
|
||||
const existing =
|
||||
!refresh &&
|
||||
list('pulls?state=open&base=dev&per_page=100').find(
|
||||
(pr) =>
|
||||
pr.head.repo?.full_name === repository &&
|
||||
pr.user.login === 'github-actions[bot]' &&
|
||||
branchTag(pr.head.ref) &&
|
||||
isRc(branchTag(pr.head.ref)) === (channel === 'rc') &&
|
||||
(!requested || branchTag(pr.head.ref) === requested),
|
||||
)
|
||||
if (existing) {
|
||||
api(`issues/${existing.number}/labels`, { labels: ['release'] })
|
||||
output({ existing_pr: existing.html_url })
|
||||
summary(
|
||||
`Existing version PR: ${existing.html_url}\nClose it before preparing a replacement; its candidate is unchanged.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
const base = (requested || `v${json('package.json').version}`).split(
|
||||
/[-+]/,
|
||||
)[0]
|
||||
if (!stablePattern.test(base))
|
||||
throw new Error(`Invalid base version: ${base}`)
|
||||
const refs = remoteRefs().map(([, ref]) => ref)
|
||||
const tags = refs
|
||||
.filter((ref) => ref.startsWith('refs/tags/'))
|
||||
.map((ref) => ref.slice(10))
|
||||
const reserved = refs
|
||||
.filter((ref) => ref.startsWith('refs/heads/'))
|
||||
.filter((ref) => !refresh || ref !== `refs/heads/${refresh.head.ref}`)
|
||||
.map(
|
||||
(ref) => branchTag(ref.slice(11)) || branchTag(ref.slice(11), 'publish/'),
|
||||
)
|
||||
.filter(Boolean)
|
||||
const sameBase = (tag) => isRc(tag) && tag.startsWith(`${base}-rc`)
|
||||
const occupied = [...tags, ...reserved]
|
||||
const last = latest(occupied.filter(sameBase))
|
||||
const tag =
|
||||
requested ||
|
||||
(channel === 'stable'
|
||||
? base
|
||||
: last
|
||||
? `${base}-rc.${BigInt(last.match(rcPattern)[4] ?? 0) + 1n}`
|
||||
: `${base}-rc`)
|
||||
if (occupied.includes(tag))
|
||||
throw new Error(`Tag ${tag} already exists or is reserved.`)
|
||||
const sha = git('rev-parse', 'HEAD')
|
||||
const body = releaseBody(tag, sha, tags, false)
|
||||
summary(body)
|
||||
if (
|
||||
remoteRefs().some(
|
||||
([, ref]) =>
|
||||
ref === `refs/tags/${tag}` || ref === `refs/heads/publish/${tag}`,
|
||||
)
|
||||
)
|
||||
throw new Error(`Tag ${tag} already exists or is reserved for publication.`)
|
||||
if (json('package.json').version !== tag.slice(1))
|
||||
run('node', ['scripts/release-version.mjs', tag])
|
||||
validateVersions(tag)
|
||||
const title = titleFor(tag)
|
||||
const branch = refresh
|
||||
? `release-refresh/${env.GITHUB_RUN_ID}-${env.GITHUB_RUN_ATTEMPT}`
|
||||
: `release/${tag}`
|
||||
writeVersionPr({ sha, body, refresh, title, branch, files: versionFiles })
|
||||
}
|
||||
|
||||
function releaseBody(tag, sha, tags, publishing) {
|
||||
const previous =
|
||||
(isRc(tag) &&
|
||||
latest(
|
||||
tags.filter(
|
||||
(value) =>
|
||||
isRc(value) &&
|
||||
value.startsWith(`${tag.split('-')[0]}-rc`) &&
|
||||
value !== tag,
|
||||
),
|
||||
)) ||
|
||||
latest(tags.filter((value) => stablePattern.test(value) && value !== tag))
|
||||
const url = `${env.GITHUB_SERVER_URL}/${repository}`
|
||||
let range = sha
|
||||
let comparison = 'No previous release tag'
|
||||
if (previous) {
|
||||
git('fetch', '--no-tags', 'origin', `refs/tags/${previous}`)
|
||||
range = `${git('rev-parse', 'FETCH_HEAD^{commit}')}..${sha}`
|
||||
comparison = `Changes since **${previous}** · [Compare changes](${url}/compare/${previous}...${sha})`
|
||||
}
|
||||
comparison += ` · **${git('rev-list', '--count', range)} commits**`
|
||||
const commits = git('log', '--format=%h %s', range)
|
||||
const groups = Object.groupBy(commits ? commits.split('\n') : [], (line) => {
|
||||
if (/^\S+ chore\(deps\)!?: /i.test(line)) return 'deps'
|
||||
const type = line.match(/^\S+ (\w+)(?:\([^)]*\))?!?: /)?.[1]?.toLowerCase()
|
||||
return type === 'doc' ? 'docs' : type || 'other'
|
||||
})
|
||||
const labels = {
|
||||
fix: 'Fixes',
|
||||
feat: 'Features',
|
||||
perf: 'Performance',
|
||||
revert: 'Reverts',
|
||||
refactor: 'Refactoring',
|
||||
build: 'Build',
|
||||
deps: 'Dependencies',
|
||||
ci: 'CI',
|
||||
docs: 'Documentation',
|
||||
test: 'Tests',
|
||||
chore: 'Maintenance',
|
||||
style: 'Style',
|
||||
other: 'Other',
|
||||
}
|
||||
const names = {
|
||||
macos: 'macOS',
|
||||
windows: 'Windows',
|
||||
ui: 'UI',
|
||||
ci: 'CI',
|
||||
tun: 'TUN',
|
||||
}
|
||||
const order = Object.keys(labels)
|
||||
const rank = (type) =>
|
||||
order.includes(type) ? order.indexOf(type) : order.length
|
||||
const scope =
|
||||
Object.entries(groups)
|
||||
.sort(([a], [b]) => rank(a) - rank(b) || a.localeCompare(b))
|
||||
.map(([type, lines]) => {
|
||||
const entries = lines.map((line) => {
|
||||
const hash = line.slice(0, line.indexOf(' '))
|
||||
const title = line
|
||||
.slice(hash.length + 1)
|
||||
.replace(/\s*\((?:[\w.-]+\/[\w.-]+)?#\d+\)/g, '')
|
||||
.replace(/(?:[\w.-]+\/[\w.-]+)?#\d+\b/g, '')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim()
|
||||
.replace(
|
||||
/^\w+(?:\(([^)]*)\))?(!)?:\s*/,
|
||||
(_, scope, breaking) =>
|
||||
`${breaking ? 'Breaking: ' : ''}${scope ? `${Object.hasOwn(names, scope) ? names[scope] : scope}: ` : ''}`,
|
||||
)
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replace(/[\\`*_[\]]/g, '\\$&')
|
||||
return `- ${title} [#${hash}](${url}/commit/${hash})`
|
||||
})
|
||||
return `### ${Object.hasOwn(labels, type) ? labels[type] : type} · ${lines.length}\n\n${entries.join('\n')}`
|
||||
})
|
||||
.join('\n\n') || 'No new commits.'
|
||||
return `## ${titleFor(tag)}
|
||||
|
||||
Source: \`dev\` · [${sha}](${url}/commit/${sha}) \n${comparison}
|
||||
${
|
||||
publishing
|
||||
? `<!-- release-source:${sha} -->
|
||||
|
||||
After approval, select the checkbox below to publish.
|
||||
Do not use the normal Squash or Rebase merge buttons.
|
||||
|
||||
- [ ] ${publishLabel}`
|
||||
: `
|
||||
- [ ] ${refreshLabel}
|
||||
|
||||
Refreshing requires a new approval.`
|
||||
}
|
||||
|
||||
## Changes
|
||||
|
||||
${scope}
|
||||
`
|
||||
}
|
||||
|
||||
function writeVersionPr({ sha, body, refresh, title, branch, files }) {
|
||||
// Create-only ref and expectedHeadOid prevent replacing another candidate.
|
||||
api('git/refs', { ref: `refs/heads/${branch}`, sha })
|
||||
let pr
|
||||
try {
|
||||
const commit = api('graphql', {
|
||||
query: `mutation($input: CreateCommitOnBranchInput!) {
|
||||
createCommitOnBranch(input: $input) { commit { oid } }
|
||||
}`,
|
||||
variables: {
|
||||
input: {
|
||||
branch: { repositoryNameWithOwner: repository, branchName: branch },
|
||||
expectedHeadOid: sha,
|
||||
message: { headline: title },
|
||||
fileChanges: {
|
||||
additions: files.map((path) => ({
|
||||
path,
|
||||
contents: readFileSync(path).toString('base64'),
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if (!commit.data?.createCommitOnBranch?.commit?.oid)
|
||||
throw new Error('Signed version commit failed.')
|
||||
if (refresh) {
|
||||
const current = get(`pulls/${refresh.number}`)
|
||||
if (
|
||||
current.state !== 'open' ||
|
||||
current.head.sha !== refresh.head.sha ||
|
||||
current.base.ref !== refresh.base.ref ||
|
||||
current.body !== refresh.body
|
||||
)
|
||||
throw new Error(
|
||||
'The version pull request changed while preparing the update.',
|
||||
)
|
||||
const oid = commit.data.createCommitOnBranch.commit.oid
|
||||
updateRefs(refresh.base.repo.node_id, [
|
||||
{
|
||||
name: `refs/heads/${refresh.head.ref}`,
|
||||
beforeOid: refresh.head.sha,
|
||||
afterOid: oid,
|
||||
force: true,
|
||||
},
|
||||
{
|
||||
name: `refs/heads/${branch}`,
|
||||
beforeOid: oid,
|
||||
afterOid: '0'.repeat(40),
|
||||
},
|
||||
])
|
||||
for (const review of list(
|
||||
`pulls/${refresh.number}/reviews?per_page=100`,
|
||||
)) {
|
||||
if (review.state === 'APPROVED')
|
||||
api(
|
||||
`pulls/${refresh.number}/reviews/${review.id}/dismissals`,
|
||||
{
|
||||
message:
|
||||
'The version PR was refreshed from dev; please review again.',
|
||||
},
|
||||
'PUT',
|
||||
)
|
||||
}
|
||||
pr = api(`pulls/${refresh.number}`, { title, body }, 'PATCH')
|
||||
} else {
|
||||
pr = api('pulls', {
|
||||
head: branch,
|
||||
base: 'dev',
|
||||
title,
|
||||
body,
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
if (refresh) {
|
||||
try {
|
||||
api(`git/refs/heads/${branch}`, {}, 'DELETE')
|
||||
} catch {}
|
||||
}
|
||||
throw error
|
||||
}
|
||||
api(`issues/${pr.number}/labels`, { labels: ['release'] })
|
||||
summary(`Version pull request: ${pr.html_url}`)
|
||||
}
|
||||
|
||||
function updateRefs(repositoryId, refUpdates) {
|
||||
api('graphql', {
|
||||
query: `mutation($input: UpdateRefsInput!) { updateRefs(input: $input) { clientMutationId } }`,
|
||||
variables: { input: { repositoryId, refUpdates } },
|
||||
})
|
||||
}
|
||||
|
||||
function requireBotPr(pr, base, prefix) {
|
||||
const tag = branchTag(pr.head.ref, prefix)
|
||||
if (
|
||||
!tag ||
|
||||
pr.base.ref !== base ||
|
||||
pr.base.repo.full_name !== repository ||
|
||||
pr.head.repo?.full_name !== repository ||
|
||||
pr.user.login !== 'github-actions[bot]'
|
||||
)
|
||||
throw new Error(
|
||||
'Expected a release PR created by this repository workflow.',
|
||||
)
|
||||
return tag
|
||||
}
|
||||
|
||||
function publishPr() {
|
||||
const event = json(env.GITHUB_EVENT_PATH)
|
||||
const pr = get(`pulls/${event.pull_request.number}`)
|
||||
const tag = requireBotPr(pr, 'dev', 'release/')
|
||||
if (!pr.merged || pr.merge_commit_sha !== event.pull_request.merge_commit_sha)
|
||||
throw new Error('Expected the final merged version commit on dev.')
|
||||
const sha = pr.merge_commit_sha
|
||||
fetchBranches()
|
||||
git('fetch', '--no-tags', 'origin', sha)
|
||||
git('merge-base', '--is-ancestor', sha, 'origin/dev')
|
||||
validateVersionCommit(tag, sha)
|
||||
const branch = `publish/${tag}`
|
||||
const existing = list(
|
||||
`pulls?state=all&base=main&head=${repository.split('/')[0]}:${branch}&per_page=100`,
|
||||
)
|
||||
if (existing.length) {
|
||||
const publication = existing[0]
|
||||
requireBotPr(publication, 'main', 'publish/')
|
||||
if (publication.head.sha !== sha)
|
||||
throw new Error(
|
||||
'This tag is already reserved by a different publication snapshot.',
|
||||
)
|
||||
summary(`Existing publication PR: ${publication.html_url}`)
|
||||
return
|
||||
}
|
||||
const refs = remoteRefs()
|
||||
if (refs.some(([, ref]) => ref === `refs/tags/${tag}`))
|
||||
throw new Error(`Tag ${tag} already exists.`)
|
||||
git('merge-base', '--is-ancestor', 'origin/main', sha)
|
||||
const head = refs.find(([, ref]) => ref === `refs/heads/${branch}`)?.[0]
|
||||
if (head && head !== sha)
|
||||
throw new Error('Publication branch already points to another commit.')
|
||||
if (!head) api('git/refs', { ref: `refs/heads/${branch}`, sha })
|
||||
const body = releaseBody(
|
||||
tag,
|
||||
sha,
|
||||
refs
|
||||
.filter(([, ref]) => ref.startsWith('refs/tags/'))
|
||||
.map(([, ref]) => ref.slice(10)),
|
||||
true,
|
||||
)
|
||||
const publication = api('pulls', {
|
||||
head: branch,
|
||||
base: 'main',
|
||||
title: titleFor(tag),
|
||||
body,
|
||||
})
|
||||
api(`issues/${publication.number}/labels`, { labels: ['release'] })
|
||||
summary(`Publication PR: ${publication.html_url}\n\n${body}`)
|
||||
}
|
||||
|
||||
function requireApproval(pr, sha) {
|
||||
const reviews = new Map()
|
||||
for (const review of list(`pulls/${pr.number}/reviews?per_page=100`)) {
|
||||
if (['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED'].includes(review.state))
|
||||
reviews.set(review.user.login, review)
|
||||
}
|
||||
let approved = false
|
||||
for (const review of reviews.values()) {
|
||||
if (!canWrite(review.user.login)) continue
|
||||
if (review.state === 'CHANGES_REQUESTED')
|
||||
throw new Error('A reviewer with write access has requested changes.')
|
||||
if (review.state === 'APPROVED' && review.commit_id === sha) approved = true
|
||||
}
|
||||
if (!approved)
|
||||
throw new Error(
|
||||
'The current PR head needs approval from a reviewer with write access.',
|
||||
)
|
||||
}
|
||||
|
||||
function releaseOutput(tag, sha) {
|
||||
output({
|
||||
release_tag: tag,
|
||||
source_sha: sha,
|
||||
channel: isRc(tag) ? 'rc' : 'stable',
|
||||
})
|
||||
}
|
||||
|
||||
function publish() {
|
||||
const event = json(env.GITHUB_EVENT_PATH)
|
||||
const tag = requireBotPr(event.pull_request, 'main', 'publish/')
|
||||
if (
|
||||
checked(event.changes?.body?.from, publishLabel) ||
|
||||
!checked(event.pull_request.body, publishLabel)
|
||||
)
|
||||
throw new Error('Publishing requires a new checkbox selection.')
|
||||
if (!canWrite(event.sender.login))
|
||||
throw new Error('Publishing requires write access.')
|
||||
const sha = event.pull_request.head.sha
|
||||
const pr = get(`pulls/${event.pull_request.number}`)
|
||||
requireBotPr(pr, 'main', 'publish/')
|
||||
if (
|
||||
pr.head.sha !== sha ||
|
||||
!checked(pr.body, publishLabel) ||
|
||||
!pr.body.includes(`<!-- release-source:${sha} -->`)
|
||||
)
|
||||
throw new Error(
|
||||
'The publication snapshot changed after the checkbox selection.',
|
||||
)
|
||||
fetchBranches()
|
||||
git('fetch', '--no-tags', 'origin', sha)
|
||||
git('merge-base', '--is-ancestor', sha, 'origin/dev')
|
||||
validateVersionCommit(tag, sha)
|
||||
const marker = `Release workflow run: ${env.GITHUB_RUN_ID}\nSource: ${sha}\nPR: ${pr.number}`
|
||||
const existing = remoteRefs().find(([, ref]) => ref === `refs/tags/${tag}`)
|
||||
if (existing) {
|
||||
const ref = get(`git/ref/tags/${tag}`)
|
||||
const object =
|
||||
ref.object.type === 'tag' && get(`git/tags/${ref.object.sha}`)
|
||||
if (
|
||||
!object ||
|
||||
object.object.type !== 'commit' ||
|
||||
object.object.sha !== sha ||
|
||||
object.message.trim() !== marker ||
|
||||
Number(env.GITHUB_RUN_ATTEMPT) <= 1
|
||||
)
|
||||
throw new Error(
|
||||
'An existing tag can only be recovered by its original release run.',
|
||||
)
|
||||
git('merge-base', '--is-ancestor', sha, 'origin/main')
|
||||
summary(`Resuming ${tag} at ${sha} from this release run.`)
|
||||
} else {
|
||||
if (pr.state !== 'open' || pr.draft)
|
||||
throw new Error('Expected an open, ready publication PR.')
|
||||
requireApproval(pr, sha)
|
||||
const main = git('rev-parse', 'origin/main')
|
||||
git('merge-base', '--is-ancestor', main, sha)
|
||||
const object = api('git/tags', {
|
||||
tag,
|
||||
message: marker,
|
||||
object: sha,
|
||||
type: 'commit',
|
||||
})
|
||||
// The tag records run ownership in the same transaction as the fast-forward.
|
||||
updateRefs(pr.base.repo.node_id, [
|
||||
{ name: 'refs/heads/main', beforeOid: main, afterOid: sha, force: false },
|
||||
{
|
||||
name: `refs/heads/${pr.head.ref}`,
|
||||
beforeOid: sha,
|
||||
afterOid: sha,
|
||||
force: false,
|
||||
},
|
||||
{
|
||||
name: `refs/tags/${tag}`,
|
||||
beforeOid: '0'.repeat(40),
|
||||
afterOid: object.sha,
|
||||
force: false,
|
||||
},
|
||||
])
|
||||
summary(`Fast-forwarded main and tagged ${tag} at approved commit ${sha}.`)
|
||||
}
|
||||
releaseOutput(tag, sha)
|
||||
}
|
||||
|
||||
function validateTag() {
|
||||
const tag = env.GITHUB_REF_NAME
|
||||
if (!isRelease(tag)) throw new Error('Expected a stable or RC release tag.')
|
||||
fetchBranches()
|
||||
const sha = git('rev-parse', `${env.GITHUB_SHA}^{commit}`)
|
||||
const ref = get(`git/ref/tags/${tag}`)
|
||||
const object = ref.object.type === 'tag' && get(`git/tags/${ref.object.sha}`)
|
||||
if (object && object.message.includes('Release workflow run:'))
|
||||
throw new Error(
|
||||
'Resume the original publication run for workflow-owned tags.',
|
||||
)
|
||||
git('fetch', '--no-tags', 'origin', `refs/tags/${tag}`)
|
||||
if (git('rev-parse', 'FETCH_HEAD^{commit}') !== sha)
|
||||
throw new Error('The tag moved after this run started.')
|
||||
for (const branch of ['main', 'dev'])
|
||||
git('merge-base', '--is-ancestor', sha, `origin/${branch}`)
|
||||
validateVersions(tag, sha)
|
||||
releaseOutput(tag, sha)
|
||||
}
|
||||
|
||||
function prepareDraft() {
|
||||
const tag = env.RELEASE_TAG
|
||||
verifyTarget()
|
||||
const release = list('releases?per_page=100').find(
|
||||
(release) => release.tag_name === tag,
|
||||
)
|
||||
if (release && !release.draft)
|
||||
throw new Error('This release is already public.')
|
||||
const draft =
|
||||
release ||
|
||||
api('releases', {
|
||||
tag_name: tag,
|
||||
target_commitish: env.SOURCE_SHA,
|
||||
name: `Clash Verge Rev ${tag}`,
|
||||
body: 'Draft release, will be updated later.',
|
||||
draft: true,
|
||||
prerelease: isRc(tag),
|
||||
})
|
||||
output({ id: draft.id })
|
||||
}
|
||||
|
||||
function verifyTarget(tag = env.RELEASE_TAG, sha = env.SOURCE_SHA) {
|
||||
const ref = get(`git/ref/tags/${tag}`)
|
||||
const target =
|
||||
ref.object.type === 'tag'
|
||||
? get(`git/tags/${ref.object.sha}`).object
|
||||
: ref.object
|
||||
if (target.type !== 'commit' || target.sha !== sha)
|
||||
throw new Error('The release tag no longer points to the validated source.')
|
||||
}
|
||||
|
||||
function nextDev() {
|
||||
let refresh
|
||||
let tag = env.RELEASE_TAG
|
||||
let source = env.SOURCE_SHA
|
||||
let minor = false
|
||||
if (env.GITHUB_EVENT_NAME === 'pull_request_target') {
|
||||
const event = json(env.GITHUB_EVENT_PATH)
|
||||
const oldBody = event.changes?.body?.from
|
||||
const body = event.pull_request.body
|
||||
if (
|
||||
checked(oldBody, minorLabel) === checked(body, minorLabel) &&
|
||||
(checked(oldBody) || !checked(body))
|
||||
)
|
||||
return
|
||||
if (!canWrite(event.sender.login))
|
||||
throw new Error('Changing the next dev version requires write access.')
|
||||
refresh = get(`pulls/${event.pull_request.number}`)
|
||||
if (refresh.state !== 'open') return
|
||||
tag = requireBotPr(refresh, 'dev', 'next-dev/')
|
||||
if (
|
||||
refresh.head.sha !== event.pull_request.head.sha ||
|
||||
refresh.body !== body
|
||||
)
|
||||
throw new Error(
|
||||
'The version update PR changed after the checkbox selection.',
|
||||
)
|
||||
minor = checked(body, minorLabel)
|
||||
source = body.match(/<!-- next-dev-source:([a-f0-9]{40}) -->/)?.[1]
|
||||
}
|
||||
if (!stablePattern.test(tag) || !/^[a-f0-9]{40}$/.test(source))
|
||||
throw new Error('The next dev version requires a stable release snapshot.')
|
||||
verifyTarget(tag, source)
|
||||
const release = get(`releases/tags/${tag}`)
|
||||
if (release.draft || release.prerelease)
|
||||
throw new Error('The stable release must be public before preparing dev.')
|
||||
const branch = `next-dev/${tag}`
|
||||
if (!refresh) {
|
||||
const existing = list(
|
||||
`pulls?state=all&base=dev&head=${repository.split('/')[0]}:${branch}&per_page=100`,
|
||||
)[0]
|
||||
if (existing) {
|
||||
requireBotPr(existing, 'dev', 'next-dev/')
|
||||
summary(`Existing dev version PR: ${existing.html_url}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
fetchBranches()
|
||||
git('fetch', '--no-tags', 'origin', source)
|
||||
git('merge-base', '--is-ancestor', source, 'origin/main')
|
||||
git('merge-base', '--is-ancestor', source, 'origin/dev')
|
||||
git('checkout', '--detach', 'origin/dev')
|
||||
const sha = git('rev-parse', 'HEAD')
|
||||
validateVersions(tag, source)
|
||||
validateVersions(tag, sha)
|
||||
if (read('Changelog.md') !== gitFile(source, 'Changelog.md'))
|
||||
throw new Error(
|
||||
'Changelog.md changed after this release. Preserve the unreleased entries and prepare the dev update manually.',
|
||||
)
|
||||
if (
|
||||
!read('Changelog.md').split('\n').includes(`## ${tag}`) ||
|
||||
read('docs/Changelog.history.md').split('\n').includes(`## ${tag}`)
|
||||
)
|
||||
throw new Error('The released changelog is missing or already archived.')
|
||||
const [major, minorVersion, patch] = tag.slice(1).split('.').map(BigInt)
|
||||
const patchTag = `v${major}.${minorVersion}.${patch + 1n}`
|
||||
const minorTag = `v${major}.${minorVersion + 1n}.0`
|
||||
const nextTag = minor ? minorTag : patchTag
|
||||
run('pnpm', ['release-version', nextTag])
|
||||
run('bash', ['scripts-workflow/bump_changelog.sh'])
|
||||
const changelog = read('Changelog.md')
|
||||
if (!changelog.includes('## v(Version Goes Here)'))
|
||||
throw new Error('The changelog template has no version placeholder.')
|
||||
writeFileSync(
|
||||
'Changelog.md',
|
||||
changelog.replace('## v(Version Goes Here)', `## ${nextTag}`),
|
||||
)
|
||||
validateVersions(nextTag)
|
||||
const title = `Dev: ${nextTag}`
|
||||
const body = `## ${title}
|
||||
|
||||
After [${tag}](${env.GITHUB_SERVER_URL}/${repository}/releases/tag/${tag}).
|
||||
<!-- next-dev-source:${source} -->
|
||||
|
||||
Patch: \`${patchTag}\` · Minor: \`${minorTag}\`
|
||||
|
||||
- [${minor ? 'x' : ' '}] ${minorLabel}
|
||||
- [ ] ${refreshLabel}
|
||||
|
||||
Changing the version or refreshing requires a new approval.
|
||||
`
|
||||
writeVersionPr({
|
||||
sha,
|
||||
body,
|
||||
refresh,
|
||||
title,
|
||||
branch: refresh
|
||||
? `next-dev-refresh/${env.GITHUB_RUN_ID}-${env.GITHUB_RUN_ATTEMPT}`
|
||||
: branch,
|
||||
files: [...versionFiles, 'Changelog.md', 'docs/Changelog.history.md'],
|
||||
})
|
||||
}
|
||||
|
||||
const commands = {
|
||||
prepare,
|
||||
'next-dev': nextDev,
|
||||
'publish-pr': publishPr,
|
||||
publish,
|
||||
'validate-tag': validateTag,
|
||||
'prepare-draft': prepareDraft,
|
||||
'verify-target': verifyTarget,
|
||||
}
|
||||
const command = commands[process.argv[2]]
|
||||
if (!command) throw new Error('Unknown release command.')
|
||||
command()
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "2.5.9-rc"
|
||||
version = "2.5.9"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
@@ -29,7 +29,7 @@ perf-harness = ["dep:tauri-plugin-wdio-webdriver"]
|
||||
identifier = "io.github.clash-verge-rev.clash-verge-rev"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.7.3", features = [] }
|
||||
tauri-build = { version = "2.7.4", features = [] }
|
||||
|
||||
[dependencies]
|
||||
clash-verge-draft = { workspace = true }
|
||||
@@ -72,12 +72,12 @@ sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs.git", branch
|
||||
"guard",
|
||||
] }
|
||||
network-interface = { version = "2.0.5", features = ["serde"] }
|
||||
tauri-plugin-shell = "2.5.0"
|
||||
tauri-plugin-shell = "2.6.0"
|
||||
tauri-plugin-opener = "2.7.2"
|
||||
tauri-plugin-dialog = "2.8.3"
|
||||
tauri-plugin-dialog = "2.8.4"
|
||||
tauri-plugin-fs = "2.7.1"
|
||||
tauri-plugin-process = "2.4.0"
|
||||
tauri-plugin-deep-link = "2.6.2"
|
||||
tauri-plugin-deep-link = "2.6.3"
|
||||
tauri-plugin-window-state = "2.5.0"
|
||||
zip = "9.1.3"
|
||||
flate2 = "1.1.10"
|
||||
@@ -90,12 +90,12 @@ getrandom = "0.4.3"
|
||||
futures = "0.3.34"
|
||||
gethostname = "1.1.0"
|
||||
scopeguard = "1.2.0"
|
||||
tauri-plugin-notification = "2.7.0"
|
||||
tauri-plugin-notification = "2.8.0"
|
||||
tokio-stream = "0.1.19"
|
||||
backon = { version = "1.6.0", features = ["tokio-sleep"] }
|
||||
tauri-plugin-http = "2.8.3"
|
||||
tracing = { workspace = true }
|
||||
tauri-plugin-devtools = { version = "2.2.2", optional = true }
|
||||
tauri-plugin-devtools = { version = "2.2.3", optional = true }
|
||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo", rev = "7a03d16f4d39b1bb885b7babe66b9e153e34b615" }
|
||||
async-trait = "0.1.92"
|
||||
clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.7.6", version = "2.7.6", features = [
|
||||
@@ -109,7 +109,7 @@ dark-light = "3.0.0"
|
||||
bytes = "1.12.1"
|
||||
tokio-util = { version = "0.7.20", features = ["time"] }
|
||||
specta = { version = "=2.0.0-rc.25", features = ["derive", "function", "serde_json"] }
|
||||
tauri-specta = { version = "=2.0.0-rc.25", features = ["derive", "typescript"] }
|
||||
tauri-specta = { version = "=2.0.0-rc.26", features = ["derive", "typescript"] }
|
||||
specta-typescript = "=0.0.12"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
@@ -120,7 +120,7 @@ libc = "0.2.191"
|
||||
clash-verge-signal = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
tauri-plugin-wdio-webdriver = { version = "=1.5.0", optional = true }
|
||||
tauri-plugin-wdio-webdriver = { version = "=1.5.1", optional = true }
|
||||
objc2 = "0.6.5"
|
||||
objc2-foundation = { version = "0.3.2", features = [
|
||||
"NSString",
|
||||
|
||||
@@ -109,7 +109,7 @@ impl AutoBackupManager {
|
||||
{
|
||||
*self.settings.write() = settings;
|
||||
}
|
||||
let _ = self.settings_tx.send_replace(settings);
|
||||
let _ = self.settings_tx.send(settings);
|
||||
self.maybe_start_runner(settings);
|
||||
Ok(())
|
||||
}
|
||||
@@ -119,7 +119,7 @@ impl AutoBackupManager {
|
||||
{
|
||||
*self.settings.write() = settings;
|
||||
}
|
||||
let _ = self.settings_tx.send_replace(settings);
|
||||
let _ = self.settings_tx.send(settings);
|
||||
self.maybe_start_runner(settings);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ pub async fn patch_verge(patch: &IVerge, not_save_file: bool) -> Result<()> {
|
||||
|
||||
/// Apply a patch without post-update reconciliation.
|
||||
pub(super) async fn apply_verge_patch(patch: &IVerge, not_save_file: bool) -> Result<()> {
|
||||
let config_write = Config::lock_config_write().await;
|
||||
let config_write = Config::try_lock_config_write()?;
|
||||
apply_verge_patch_locked(&config_write, patch, not_save_file).await
|
||||
}
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ pub async fn hide() {
|
||||
{
|
||||
let _ = window.hide();
|
||||
}
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -289,6 +289,9 @@ pub fn run() -> std::process::ExitCode {
|
||||
}
|
||||
|
||||
pub fn handle_window_close(api: &tauri::WindowEvent) {
|
||||
#[cfg(target_os = "macos")]
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
|
||||
if core::handle::Handle::global().is_exiting() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.5.9-rc",
|
||||
"version": "2.5.9",
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"bundle": {
|
||||
"active": true,
|
||||
|
||||
@@ -40,9 +40,9 @@ export const BackupConfigViewer = memo(
|
||||
|
||||
const { register, handleSubmit, watch } = useForm<IWebDavConfig>({
|
||||
defaultValues: {
|
||||
url: webdav_url ?? '',
|
||||
username: webdav_username ?? '',
|
||||
password: webdav_password ?? '',
|
||||
url: webdav_url!,
|
||||
username: webdav_username!,
|
||||
password: webdav_password!,
|
||||
},
|
||||
})
|
||||
const url = watch('url')
|
||||
@@ -50,9 +50,9 @@ export const BackupConfigViewer = memo(
|
||||
const password = watch('password')
|
||||
|
||||
const webdavChanged =
|
||||
(webdav_url ?? '') !== url ||
|
||||
(webdav_username ?? '') !== username ||
|
||||
(webdav_password ?? '') !== password
|
||||
webdav_url !== url ||
|
||||
webdav_username !== username ||
|
||||
webdav_password !== password
|
||||
|
||||
const webdavSignature = buildWebdavSignature(verge)
|
||||
const webdavStatus = getWebdavStatus(webdavSignature)
|
||||
@@ -69,9 +69,9 @@ export const BackupConfigViewer = memo(
|
||||
}, [webdav_url, webdav_username, webdav_password, onInit, shouldAutoInit])
|
||||
|
||||
const checkForm = () => {
|
||||
const username = usernameRef.current?.value.trim()
|
||||
const username = usernameRef.current?.value
|
||||
const password = passwordRef.current?.value
|
||||
const url = urlRef.current?.value.trim()
|
||||
const url = urlRef.current?.value
|
||||
|
||||
if (!url) {
|
||||
urlRef.current?.focus()
|
||||
@@ -95,15 +95,14 @@ export const BackupConfigViewer = memo(
|
||||
}
|
||||
|
||||
const save = useLockFn(async (data: IWebDavConfig) => {
|
||||
const trimmedUrl = data.url.trim()
|
||||
const trimmedUsername = data.username.trim()
|
||||
const isClearing = !trimmedUrl && !trimmedUsername && !data.password
|
||||
if (!isClearing) checkForm()
|
||||
checkForm()
|
||||
const signature = buildWebdavSignature({
|
||||
webdav_url: data.url,
|
||||
webdav_username: data.username,
|
||||
webdav_password: data.password,
|
||||
})
|
||||
const trimmedUrl = data.url.trim()
|
||||
const trimmedUsername = data.username.trim()
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
@@ -128,7 +127,7 @@ export const BackupConfigViewer = memo(
|
||||
)
|
||||
setWebdavStatus(signature, 'unknown')
|
||||
showNotice.success('settings.modals.backup.messages.webdavConfigSaved')
|
||||
if (!isClearing) await onSaveSuccess(signature)
|
||||
await onSaveSuccess(signature)
|
||||
} catch (error) {
|
||||
showNotice.error(
|
||||
'settings.modals.backup.messages.webdavConfigSaveFailed',
|
||||
@@ -224,9 +223,9 @@ export const BackupConfigViewer = memo(
|
||||
}}
|
||||
>
|
||||
{webdavChanged ||
|
||||
!webdav_url ||
|
||||
!webdav_username ||
|
||||
!webdav_password ? (
|
||||
webdav_url === undefined ||
|
||||
webdav_username === undefined ||
|
||||
webdav_password === undefined ? (
|
||||
<Button
|
||||
variant="contained"
|
||||
color={'primary'}
|
||||
|
||||
@@ -72,10 +72,12 @@ const LazyReactMarkdown = lazy(async () => {
|
||||
{ default: ReactMarkdown },
|
||||
{ default: rehypeRaw },
|
||||
{ default: rehypeSanitize, defaultSchema },
|
||||
{ default: remarkGfm },
|
||||
] = await Promise.all([
|
||||
import('react-markdown'),
|
||||
import('rehype-raw'),
|
||||
import('rehype-sanitize'),
|
||||
import('remark-gfm'),
|
||||
])
|
||||
|
||||
const sanitizeSchema = {
|
||||
@@ -102,6 +104,7 @@ const LazyReactMarkdown = lazy(async () => {
|
||||
default: (props: ReactMarkdownOptions) => (
|
||||
<ReactMarkdown
|
||||
{...props}
|
||||
remarkPlugins={[remarkGfm, ...(props.remarkPlugins ?? [])]}
|
||||
rehypePlugins={[rehypeRaw, [rehypeSanitize, sanitizeSchema]]}
|
||||
/>
|
||||
),
|
||||
|
||||
@@ -43,11 +43,7 @@ export const getWebdavStatus = (signature: string): WebdavStatus => {
|
||||
}
|
||||
|
||||
export const setWebdavStatus = (signature: string, status: WebdavStatus) => {
|
||||
if (!canUseStorage()) return
|
||||
if (!signature) {
|
||||
localStorage.removeItem(WEBDAV_STATUS_KEY)
|
||||
return
|
||||
}
|
||||
if (!signature || !canUseStorage()) return
|
||||
|
||||
const payload: WebdavStatusCache = {
|
||||
signature,
|
||||
|
||||
Reference in New Issue
Block a user