mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-08 02:52:07 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea509b8236 | ||
|
|
52d616302c | ||
|
|
8ddd99f226 | ||
|
|
e0e97a920e | ||
|
|
c4f9d65e07 | ||
|
|
0c7e0c8535 | ||
|
|
1638ab48d8 | ||
|
|
5d7dc3aed9 |
@@ -5,7 +5,7 @@
|
|||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/node:2": {
|
"ghcr.io/devcontainers/features/node:2": {
|
||||||
"version": "24.21.0",
|
"version": "24.21.0",
|
||||||
"pnpmVersion": "12.5.1"
|
"pnpmVersion": "12.8.1"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/rust:1": {
|
"ghcr.io/devcontainers/features/rust:1": {
|
||||||
"version": "1.98.1",
|
"version": "1.98.1",
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
"version": "v9.0.0",
|
"version": "v9.0.0",
|
||||||
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
|
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
|
||||||
},
|
},
|
||||||
"github/gh-aw-actions/setup@v0.89.15": {
|
"github/gh-aw-actions/setup@v0.89.21": {
|
||||||
"repo": "github/gh-aw-actions/setup",
|
"repo": "github/gh-aw-actions/setup",
|
||||||
"version": "v0.89.15",
|
"version": "v0.89.21",
|
||||||
"sha": "045beb2d14bda8d0c1f2e83b41527f63770d2855"
|
"sha": "924af5fdc64061cfbf66fb584c8b07e2ac230c60"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"containers": {
|
"containers": {
|
||||||
@@ -27,6 +27,11 @@
|
|||||||
"digest": "sha256:57a3e27388a6d7d32719088581e52567727fa0bf2f0d477bf565b0c4baa12a3f",
|
"digest": "sha256:57a3e27388a6d7d32719088581e52567727fa0bf2f0d477bf565b0c4baa12a3f",
|
||||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.28.16@sha256:57a3e27388a6d7d32719088581e52567727fa0bf2f0d477bf565b0c4baa12a3f"
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.28.16@sha256:57a3e27388a6d7d32719088581e52567727fa0bf2f0d477bf565b0c4baa12a3f"
|
||||||
},
|
},
|
||||||
|
"ghcr.io/github/gh-aw-firewall/agent:0.28.23": {
|
||||||
|
"image": "ghcr.io/github/gh-aw-firewall/agent:0.28.23",
|
||||||
|
"digest": "sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2",
|
||||||
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2"
|
||||||
|
},
|
||||||
"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.13": {
|
"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.13": {
|
||||||
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.13",
|
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.13",
|
||||||
"digest": "sha256:61f12dcff38eb008b645d87a5541763452f409d9040eb243718764944167b1a2",
|
"digest": "sha256:61f12dcff38eb008b645d87a5541763452f409d9040eb243718764944167b1a2",
|
||||||
@@ -42,6 +47,11 @@
|
|||||||
"digest": "sha256:cd400948638ffe1b87ec319abf73fa29b6ac9881b015da58bba971c4cc13a400",
|
"digest": "sha256:cd400948638ffe1b87ec319abf73fa29b6ac9881b015da58bba971c4cc13a400",
|
||||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.16@sha256:cd400948638ffe1b87ec319abf73fa29b6ac9881b015da58bba971c4cc13a400"
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.16@sha256:cd400948638ffe1b87ec319abf73fa29b6ac9881b015da58bba971c4cc13a400"
|
||||||
},
|
},
|
||||||
|
"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23": {
|
||||||
|
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23",
|
||||||
|
"digest": "sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64",
|
||||||
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64"
|
||||||
|
},
|
||||||
"ghcr.io/github/gh-aw-firewall/squid:0.28.13": {
|
"ghcr.io/github/gh-aw-firewall/squid:0.28.13": {
|
||||||
"image": "ghcr.io/github/gh-aw-firewall/squid:0.28.13",
|
"image": "ghcr.io/github/gh-aw-firewall/squid:0.28.13",
|
||||||
"digest": "sha256:58a8dc5be3fbafeef7da0532c38bd9047f86bf1b3c4cfd7d9b7d8d28e80a2b56",
|
"digest": "sha256:58a8dc5be3fbafeef7da0532c38bd9047f86bf1b3c4cfd7d9b7d8d28e80a2b56",
|
||||||
@@ -57,20 +67,25 @@
|
|||||||
"digest": "sha256:452197f2e241b2cda8eb0b5674960aa8ca544a64dc242e24f8263c3df6452919",
|
"digest": "sha256:452197f2e241b2cda8eb0b5674960aa8ca544a64dc242e24f8263c3df6452919",
|
||||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.28.16@sha256:452197f2e241b2cda8eb0b5674960aa8ca544a64dc242e24f8263c3df6452919"
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.28.16@sha256:452197f2e241b2cda8eb0b5674960aa8ca544a64dc242e24f8263c3df6452919"
|
||||||
},
|
},
|
||||||
"ghcr.io/github/gh-aw-mcpg:v0.4.21": {
|
"ghcr.io/github/gh-aw-firewall/squid:0.28.23": {
|
||||||
"image": "ghcr.io/github/gh-aw-mcpg:v0.4.21",
|
"image": "ghcr.io/github/gh-aw-firewall/squid:0.28.23",
|
||||||
"digest": "sha256:f26f665840660581510746ed84f5fc706f4ca8c48833757dfb4d72d86587201e",
|
"digest": "sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0",
|
||||||
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.4.21@sha256:f26f665840660581510746ed84f5fc706f4ca8c48833757dfb4d72d86587201e"
|
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0"
|
||||||
|
},
|
||||||
|
"ghcr.io/github/gh-aw-mcpg:v0.4.25": {
|
||||||
|
"image": "ghcr.io/github/gh-aw-mcpg:v0.4.25",
|
||||||
|
"digest": "sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086",
|
||||||
|
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086"
|
||||||
},
|
},
|
||||||
"ghcr.io/github/gh-aw-node": {
|
"ghcr.io/github/gh-aw-node": {
|
||||||
"image": "ghcr.io/github/gh-aw-node",
|
"image": "ghcr.io/github/gh-aw-node",
|
||||||
"digest": "sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e",
|
"digest": "sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e",
|
||||||
"pinned_image": "ghcr.io/github/gh-aw-node@sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e"
|
"pinned_image": "ghcr.io/github/gh-aw-node@sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e"
|
||||||
},
|
},
|
||||||
"ghcr.io/github/github-mcp-server:v1.12.1": {
|
"ghcr.io/github/github-mcp-server:v1.12.2": {
|
||||||
"image": "ghcr.io/github/github-mcp-server:v1.12.1",
|
"image": "ghcr.io/github/github-mcp-server:v1.12.2",
|
||||||
"digest": "sha256:0ba840c46a237879c8300e7fddb0b6347f20e029ccb9cbe2ce4a943daa1ff560",
|
"digest": "sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6",
|
||||||
"pinned_image": "ghcr.io/github/github-mcp-server:v1.12.1@sha256:0ba840c46a237879c8300e7fddb0b6347f20e029ccb9cbe2ce4a943daa1ff560"
|
"pinned_image": "ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ jobs:
|
|||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
### 稳定机场VPN推荐
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
Created at ${{ env.BUILDTIME }}.
|
||||||
EOF
|
EOF
|
||||||
@@ -580,7 +580,7 @@ jobs:
|
|||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
### 稳定机场VPN推荐
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
Created at ${{ env.BUILDTIME }}.
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install gh-aw extension
|
- name: Install gh-aw extension
|
||||||
uses: github/gh-aw-actions/setup-cli@045beb2d14bda8d0c1f2e83b41527f63770d2855 # v0.89.15
|
uses: github/gh-aw-actions/setup-cli@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
|
||||||
with:
|
with:
|
||||||
version: v0.89.15
|
version: v0.89.15
|
||||||
|
|||||||
+99
-58
File diff suppressed because one or more lines are too long
@@ -144,7 +144,7 @@ jobs:
|
|||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
### 稳定机场VPN推荐
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
Created at ${{ env.BUILDTIME }}.
|
||||||
EOF
|
EOF
|
||||||
@@ -691,7 +691,7 @@ jobs:
|
|||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
### 稳定机场VPN推荐
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
Created at ${{ env.BUILDTIME }}.
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
### 稳定机场VPN推荐
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
Created at ${{ env.BUILDTIME }}.
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
nodejs 24.21.0
|
nodejs 24.21.0
|
||||||
pnpm 12.5.1
|
pnpm 12.8.1
|
||||||
rust 1.98.1
|
rust 1.98.1
|
||||||
|
|||||||
Generated
+4
-4
@@ -1079,7 +1079,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.5.6"
|
version = "2.5.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -1223,8 +1223,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clash_verge_service_ipc"
|
name = "clash_verge_service_ipc"
|
||||||
version = "2.7.4"
|
version = "2.7.6"
|
||||||
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.7.4#b4f66bd5a365875562a622065d189e3514654b7f"
|
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.7.6#b2a7427d6681c8d3780ab83a73f4dc21da2f22d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kode-bridge",
|
"kode-bridge",
|
||||||
@@ -6922,7 +6922,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sysproxy"
|
name = "sysproxy"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
source = "git+https://github.com/clash-verge-rev/sysproxy-rs.git?branch=main#44aaf00ec9c6779e5a461a55d882eddff7841c98"
|
source = "git+https://github.com/clash-verge-rev/sysproxy-rs.git?branch=main#89ad876a0942c049ae72e1472f9fc3ed62023c5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iptools",
|
"iptools",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
+17
-13
@@ -1,31 +1,35 @@
|
|||||||
## v2.5.6
|
## v2.5.7
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong> 🐞 修复问题 </strong></summary>
|
<summary><strong> 🐞 修复问题 </strong></summary>
|
||||||
|
|
||||||
- 修复「代理集合」「规则集合」订阅响应较慢时更新误报失败、且不显示真实失败原因的问题
|
- 修复读屏软件将普通模式下的侧边栏导航项播报为不可用的可拖拽控件的问题
|
||||||
|
- 修复订阅包含自定义 DNS 时,确认开启的 DNS 覆写在重启应用后被自动关闭的问题
|
||||||
|
|
||||||
**🖥️ Windows**
|
**🖥️ Windows**
|
||||||
|
|
||||||
- 修复 Windows 部分未安装服务的用户以普通权限运行时,内核无法启动的问题
|
- 修复 Windows 系统盘根目录的删除权限被误判,导致服务模式和 TUN 无法使用的问题
|
||||||
- 修复 Windows 系统隔离权限被误判,导致服务模式和 TUN 无法使用的问题
|
- 修复 Windows 部分系统安装服务失败,提示「program not found」的问题
|
||||||
- 修复 Windows 旧版服务状态残留导致无法重装的问题,自动备份可识别的残留并恢复安装
|
|
||||||
- 修复 Windows 服务已停止时,启动要等约两分钟才显示窗口的问题
|
|
||||||
- 优化 Windows 服务安全检查失败提示:用易懂的文字说明原因,并提供修复文档链接
|
|
||||||
|
|
||||||
**🍎 macOS**
|
**🍎 macOS**
|
||||||
|
|
||||||
- macOS 修复编辑规则时「规则内容」输入的首字母被自动转为大写的问题
|
- macOS 修复启动或重启应用时偶发内核启动失败,并误提示「需要更新系统服务」的问题
|
||||||
- macOS 修复残留的服务进程导致内核无法启动、「继续使用 Sidecar」失败且无法修复的问题
|
- macOS 修复 VPN 接管网络或开机网络未就绪时的问题:服务模式内核无法启动、TUN 不可用、系统代理状态读取报错
|
||||||
- macOS 修复部分账户安装或修复服务时提示无法解析用户组而失败的问题
|
- macOS 修复用 `ipconfig set` 手动配置网卡后无法设置系统代理的问题
|
||||||
- macOS 优化用户目录在外置磁盘时服务拒绝启动内核的提示:说明原因并给出修复命令
|
|
||||||
- macOS 修复服务模式内核意外停止后,系统代理仍指向失效端口导致无法上网的问题
|
**🍎/🐧 macOS/Linux**
|
||||||
|
|
||||||
|
- 修复 macOS/Linux 服务模式停止或重启内核时直接强制结束的问题:内核来不及正常退出、最后的日志丢失
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong> 🚀 优化改进 </strong></summary>
|
<summary><strong> 🚀 优化改进 </strong></summary>
|
||||||
|
|
||||||
- 优化内核启动失败和服务模式内核意外停止的提示:显示具体原因,并在窗口恢复后提示尚未解决的错误
|
- 优化服务模式的问题排查:服务自身的运行日志会保存到文件,便于追查内核被停止的原因
|
||||||
|
|
||||||
|
**🖥️ Windows**
|
||||||
|
|
||||||
|
- 优化 Windows 服务安全检查未通过时的启动提示:不再只显示「服务无法启动内核」,直接说明原因并提供修复文档链接
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -1,3 +1,35 @@
|
|||||||
|
## v2.5.6
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong> 🐞 修复问题 </strong></summary>
|
||||||
|
|
||||||
|
- 修复「代理集合」「规则集合」订阅响应较慢时更新误报失败、且不显示真实失败原因的问题
|
||||||
|
|
||||||
|
**🖥️ Windows**
|
||||||
|
|
||||||
|
- 修复 Windows 部分未安装服务的用户以普通权限运行时,内核无法启动的问题
|
||||||
|
- 修复 Windows 系统隔离权限被误判,导致服务模式和 TUN 无法使用的问题
|
||||||
|
- 修复 Windows 旧版服务状态残留导致无法重装的问题,自动备份可识别的残留并恢复安装
|
||||||
|
- 修复 Windows 服务已停止时,启动要等约两分钟才显示窗口的问题
|
||||||
|
- 优化 Windows 服务安全检查失败提示:用易懂的文字说明原因,并提供修复文档链接
|
||||||
|
|
||||||
|
**🍎 macOS**
|
||||||
|
|
||||||
|
- macOS 修复编辑规则时「规则内容」输入的首字母被自动转为大写的问题
|
||||||
|
- macOS 修复残留的服务进程导致内核无法启动、「继续使用 Sidecar」失败且无法修复的问题
|
||||||
|
- macOS 修复部分账户安装或修复服务时提示无法解析用户组而失败的问题
|
||||||
|
- macOS 优化用户目录在外置磁盘时服务拒绝启动内核的提示:说明原因并给出修复命令
|
||||||
|
- macOS 修复服务模式内核意外停止后,系统代理仍指向失效端口导致无法上网的问题
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong> 🚀 优化改进 </strong></summary>
|
||||||
|
|
||||||
|
- 优化内核启动失败和服务模式内核意外停止的提示:显示具体原因,并在窗口恢复后提示尚未解决的错误
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## v2.5.5
|
## v2.5.5
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -34,6 +66,7 @@
|
|||||||
- 扩展配置或脚本写入由应用设置接管的字段时,弹出提示并在扩展日志中记录该值已被丢弃
|
- 扩展配置或脚本写入由应用设置接管的字段时,弹出提示并在扩展日志中记录该值已被丢弃
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## v2.5.4
|
## v2.5.4
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|||||||
+3
-3
@@ -51,11 +51,11 @@ Join [@clash_verge_rev](https://t.me/clash_verge_re) for update announcements.
|
|||||||
|
|
||||||
## Promotion
|
## Promotion
|
||||||
|
|
||||||
### ✈️ [Doggygo VPN — A Technical-Grade Proxy Service](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
### ✈️ [Doggygo VPN — A Technical-Grade Proxy Service](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
🚀 A high-performance, overseas, technical-grade proxy service offering free trials and discounted plans, fully unlocking streaming platforms and AI services. The world’s first provider to adopt the **QUIC protocol**.
|
🚀 A high-performance, overseas, technical-grade proxy service offering free trials and discounted plans, fully unlocking streaming platforms and AI services. The world’s first provider to adopt the **QUIC protocol**.
|
||||||
|
|
||||||
🎁 Register via the **Clash Verge exclusive invitation link** to receive **3 days of free trial**, with **1GB traffic per day**: 👉 [Register here](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
🎁 Register via the **Clash Verge exclusive invitation link** to receive **3 days of free trial**, with **1GB traffic per day**: 👉 [Register here](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
#### **Core Advantages:**
|
#### **Core Advantages:**
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ Join [@clash_verge_rev](https://t.me/clash_verge_re) for update announcements.
|
|||||||
- ⚡ The world’s first **QUIC-protocol-based proxy service**, now featuring faster **QUIC-family protocols** (best paired with the Clash Verge client)
|
- ⚡ The world’s first **QUIC-protocol-based proxy service**, now featuring faster **QUIC-family protocols** (best paired with the Clash Verge client)
|
||||||
- 🎬 Unlocks **streaming platforms and mainstream AI services**
|
- 🎬 Unlocks **streaming platforms and mainstream AI services**
|
||||||
|
|
||||||
🌐 Official Website: 👉 [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
🌐 Official Website: 👉 [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — AI-Powered Customer Service Platform Deeply Integrated with Crisp](https://gptkefu.com)
|
### 🤖 [GPTKefu — AI-Powered Customer Service Platform Deeply Integrated with Crisp](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -51,17 +51,17 @@ Consulta la [documentación del proyecto](https://clash-verge-rev.github.io/) pa
|
|||||||
|
|
||||||
## Promociones
|
## Promociones
|
||||||
|
|
||||||
#### [Doggygo VPN — Acelerador global orientado al rendimiento](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
#### [Doggygo VPN — Acelerador global orientado al rendimiento](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
- Servicio internacional de alto rendimiento con prueba gratuita, planes con descuento, desbloqueo de streaming y soporte de protocolo Hysteria de primera clase.
|
- Servicio internacional de alto rendimiento con prueba gratuita, planes con descuento, desbloqueo de streaming y soporte de protocolo Hysteria de primera clase.
|
||||||
- Regístrate mediante el enlace exclusivo de Clash Verge y obtén una prueba de 3 días con 1 GB de tráfico diario: [Regístrate](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Regístrate mediante el enlace exclusivo de Clash Verge y obtén una prueba de 3 días con 1 GB de tráfico diario: [Regístrate](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
- Cupón exclusivo de 20% de descuento para usuarios de Clash Verge: `verge20` (limitado a 500 usos)
|
- Cupón exclusivo de 20% de descuento para usuarios de Clash Verge: `verge20` (limitado a 500 usos)
|
||||||
- Plan promocional desde ¥15.8 al mes con 160 GB, más 20% de descuento adicional por pago anual
|
- Plan promocional desde ¥15.8 al mes con 160 GB, más 20% de descuento adicional por pago anual
|
||||||
- Equipo ubicado en el extranjero para un servicio confiable, con hasta 50% de comisión compartida
|
- Equipo ubicado en el extranjero para un servicio confiable, con hasta 50% de comisión compartida
|
||||||
- Clústeres balanceados con rutas dedicadas de alta velocidad (compatibles con clientes antiguos), latencia extremadamente baja, reproducción 4K sin interrupciones
|
- Clústeres balanceados con rutas dedicadas de alta velocidad (compatibles con clientes antiguos), latencia extremadamente baja, reproducción 4K sin interrupciones
|
||||||
- Primer proveedor global con **protocolo QUIC**, ahora con protocolos de la familia QUIC más rápidos (ideal para el cliente Clash Verge)
|
- Primer proveedor global con **protocolo QUIC**, ahora con protocolos de la familia QUIC más rápidos (ideal para el cliente Clash Verge)
|
||||||
- Desbloquea servicios de streaming y acceso a ChatGPT
|
- Desbloquea servicios de streaming y acceso a ChatGPT
|
||||||
- Sitio oficial: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Sitio oficial: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — Plataforma de atención al cliente con IA integrada con Crisp](https://gptkefu.com)
|
### 🤖 [GPTKefu — Plataforma de atención al cliente con IA integrada con Crisp](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -50,17 +50,17 @@
|
|||||||
|
|
||||||
## تبلیغات
|
## تبلیغات
|
||||||
|
|
||||||
#### [Doggygo VPN — شتابدهنده جهانی عملکردگرا](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
#### [Doggygo VPN — شتابدهنده جهانی عملکردگرا](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
- سرویس شبکه برون مرزی با عملکرد بالا به همراه دورههای آزمایشی رایگان، طرحهای تخفیفدار، امکان باز کردن قفل استریم و پشتیبانی درجه یک از پروتکل هیستریا.
|
- سرویس شبکه برون مرزی با عملکرد بالا به همراه دورههای آزمایشی رایگان، طرحهای تخفیفدار، امکان باز کردن قفل استریم و پشتیبانی درجه یک از پروتکل هیستریا.
|
||||||
- از طریق لینک اختصاصی Clash Verge ثبت نام کنید تا یک دوره آزمایشی ۳ روزه با ۱ گیگابایت ترافیک در روز دریافت کنید: [ثبت نام](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- از طریق لینک اختصاصی Clash Verge ثبت نام کنید تا یک دوره آزمایشی ۳ روزه با ۱ گیگابایت ترافیک در روز دریافت کنید: [ثبت نام](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
- کوپن تخفیف ۲۰٪ ویژه کاربران Clash Verge: `verge20` (محدود به ۵۰۰ بار استفاده)
|
- کوپن تخفیف ۲۰٪ ویژه کاربران Clash Verge: `verge20` (محدود به ۵۰۰ بار استفاده)
|
||||||
- بسته تخفیفدار از ۱۵.۸ ین در ماه برای ۱۶۰ گیگابایت، به علاوه ۲۰٪ تخفیف اضافی برای صورتحساب سالانه
|
- بسته تخفیفدار از ۱۵.۸ ین در ماه برای ۱۶۰ گیگابایت، به علاوه ۲۰٪ تخفیف اضافی برای صورتحساب سالانه
|
||||||
- توسط یک تیم خارجی با خدمات قابل اعتماد و تا 50٪ سهم درآمد اداره میشود
|
- توسط یک تیم خارجی با خدمات قابل اعتماد و تا 50٪ سهم درآمد اداره میشود
|
||||||
- کلاسترهای متعادل بار با مسیرهای اختصاصی پرسرعت (سازگار با کلاینتهای قدیمی)، تأخیر فوقالعاده کم، پخش روان 4K
|
- کلاسترهای متعادل بار با مسیرهای اختصاصی پرسرعت (سازگار با کلاینتهای قدیمی)، تأخیر فوقالعاده کم، پخش روان 4K
|
||||||
- اولین ارائهدهنده جهانی با **پروتکل QUIC**، اکنون با پروتکلهای سریعتر خانواده QUIC (بهترین ترکیب با کلاینت Clash Verge)
|
- اولین ارائهدهنده جهانی با **پروتکل QUIC**، اکنون با پروتکلهای سریعتر خانواده QUIC (بهترین ترکیب با کلاینت Clash Verge)
|
||||||
- پشتیبانی از سرویسهای استریم و دسترسی به ChatGPT
|
- پشتیبانی از سرویسهای استریم و دسترسی به ChatGPT
|
||||||
- وبسایت رسمی: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- وبسایت رسمی: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — پلتفرم خدمات مشتری هوشمند مبتنی بر هوش مصنوعی با ادغام عمیق Crisp](https://gptkefu.com)
|
### 🤖 [GPTKefu — پلتفرم خدمات مشتری هوشمند مبتنی بر هوش مصنوعی با ادغام عمیق Crisp](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -51,17 +51,17 @@ Windows (x64/x86)、Linux (x64/arm64)、macOS 10.15+ (Intel/Apple) をサポー
|
|||||||
|
|
||||||
## プロモーション
|
## プロモーション
|
||||||
|
|
||||||
#### [Doggygo VPN — 高性能グローバルアクセラレータ](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
#### [Doggygo VPN — 高性能グローバルアクセラレータ](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
- 無料トライアル、割引プラン、ストリーミング解放、世界初の Hysteria プロトコル対応を備えた高性能海外ネットワークサービス。
|
- 無料トライアル、割引プラン、ストリーミング解放、世界初の Hysteria プロトコル対応を備えた高性能海外ネットワークサービス。
|
||||||
- Clash Verge 専用リンクから登録すると、3 日間・1 日 1 GB の無料体験が利用できます。 [登録はこちら](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Clash Verge 専用リンクから登録すると、3 日間・1 日 1 GB の無料体験が利用できます。 [登録はこちら](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
- Clash Verge 利用者限定 20% オフクーポン: `verge20`(先着 500 名)
|
- Clash Verge 利用者限定 20% オフクーポン: `verge20`(先着 500 名)
|
||||||
- 月額 15.8 元で 160 GB を利用できるプラン、年額契約ならさらに 20% オフ
|
- 月額 15.8 元で 160 GB を利用できるプラン、年額契約ならさらに 20% オフ
|
||||||
- 海外チーム運営による高信頼サービス、収益シェアは最大 50%
|
- 海外チーム運営による高信頼サービス、収益シェアは最大 50%
|
||||||
- 負荷分散クラスタと高速専用回線(旧クライアント互換)、極低レイテンシで 4K も快適
|
- 負荷分散クラスタと高速専用回線(旧クライアント互換)、極低レイテンシで 4K も快適
|
||||||
- 世界初の **QUIC プロトコル**対応。より高速な QUIC 系プロトコルを提供(Clash Verge クライアントとの相性抜群)
|
- 世界初の **QUIC プロトコル**対応。より高速な QUIC 系プロトコルを提供(Clash Verge クライアントとの相性抜群)
|
||||||
- ストリーミングおよび ChatGPT の利用にも対応
|
- ストリーミングおよび ChatGPT の利用にも対応
|
||||||
- 公式サイト: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- 公式サイト: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — Crisp と深く統合された AI スマートカスタマーサービスプラットフォーム](https://gptkefu.com)
|
### 🤖 [GPTKefu — Crisp と深く統合された AI スマートカスタマーサービスプラットフォーム](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -51,17 +51,17 @@ Windows (x64/x86), Linux (x64/arm64), macOS 10.15+ (Intel/Apple)을 지원합니
|
|||||||
|
|
||||||
## 프로모션
|
## 프로모션
|
||||||
|
|
||||||
#### [Doggygo VPN — 고성능 글로벌 가속기](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
#### [Doggygo VPN — 고성능 글로벌 가속기](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
- 무료 체험, 할인 요금제, 스트리밍 해제, 선도적인 Hysteria 프로토콜 지원을 갖춘 고성능 해외 네트워크 서비스
|
- 무료 체험, 할인 요금제, 스트리밍 해제, 선도적인 Hysteria 프로토콜 지원을 갖춘 고성능 해외 네트워크 서비스
|
||||||
- Clash Verge 전용 초대 링크로 가입 시 3일간 매일 1GB 무료 체험 제공: [가입하기](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Clash Verge 전용 초대 링크로 가입 시 3일간 매일 1GB 무료 체험 제공: [가입하기](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
- Clash Verge 전용 20% 할인 코드: `verge20` (선착순 500회)
|
- Clash Verge 전용 20% 할인 코드: `verge20` (선착순 500회)
|
||||||
- 월 15.8위안부터 160GB 제공, 연간 결제 시 추가 20% 할인
|
- 월 15.8위안부터 160GB 제공, 연간 결제 시 추가 20% 할인
|
||||||
- 해외 팀 운영, 높은 신뢰성, 최대 50% 커미션
|
- 해외 팀 운영, 높은 신뢰성, 최대 50% 커미션
|
||||||
- 로드밸런싱 클러스터, 고속 전용 회선(구 클라이언트 호환), 매우 낮은 지연, 4K도 쾌적
|
- 로드밸런싱 클러스터, 고속 전용 회선(구 클라이언트 호환), 매우 낮은 지연, 4K도 쾌적
|
||||||
- 세계 최초 **QUIC 프로토콜** 지원, 더 빠른 QUIC 계열 프로토콜 제공 (Clash Verge 클라이언트와 최적의 궁합)
|
- 세계 최초 **QUIC 프로토콜** 지원, 더 빠른 QUIC 계열 프로토콜 제공 (Clash Verge 클라이언트와 최적의 궁합)
|
||||||
- 스트리밍 및 ChatGPT 접근 지원
|
- 스트리밍 및 ChatGPT 접근 지원
|
||||||
- 공식 사이트: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- 공식 사이트: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — Crisp과 긴밀히 통합된 AI 스마트 고객 서비스 플랫폼](https://gptkefu.com)
|
### 🤖 [GPTKefu — Crisp과 긴밀히 통합된 AI 스마트 고객 서비스 플랫폼](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -47,17 +47,17 @@ Clash Meta GUI базируется на <a href="https://github.com/tauri-apps/
|
|||||||
|
|
||||||
## Продвижение
|
## Продвижение
|
||||||
|
|
||||||
#### [Doggygo VPN —— технический VPN-сервис (айрпорт)](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
#### [Doggygo VPN —— технический VPN-сервис (айрпорт)](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
- Высокопроизводительный иностранный VPN-сервис (айрпорт) с бесплатным пробным периодом, выгодными тарифами, возможностью разблокировки потокового ТВ и первым в мире поддержкой протокола Hysteria.
|
- Высокопроизводительный иностранный VPN-сервис (айрпорт) с бесплатным пробным периодом, выгодными тарифами, возможностью разблокировки потокового ТВ и первым в мире поддержкой протокола Hysteria.
|
||||||
- Зарегистрируйтесь по эксклюзивной ссылке Clash Verge и получите 3 дня бесплатного использования, 1 Гб трафика в день: [регистрация](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Зарегистрируйтесь по эксклюзивной ссылке Clash Verge и получите 3 дня бесплатного использования, 1 Гб трафика в день: [регистрация](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
- Эксклюзивный промо-код на скидку 20% для Clash Verge: verge20 (только 500 штук)
|
- Эксклюзивный промо-код на скидку 20% для Clash Verge: verge20 (только 500 штук)
|
||||||
- Специальный тарифный план всего за 15,8 юаней в месяц, 160 Гб трафика, скидка 20% при оплате за год
|
- Специальный тарифный план всего за 15,8 юаней в месяц, 160 Гб трафика, скидка 20% при оплате за год
|
||||||
- Команда за рубежом, без риска побега, до 50% кэшбэка
|
- Команда за рубежом, без риска побега, до 50% кэшбэка
|
||||||
- Архитектура с балансировкойнагрузки, высокоскоростная выделенная линия (совместима со старыми клиентами), чрезвычайно низкая задержка, без проблем в часы пик, 4K видео загружается мгновенно
|
- Архитектура с балансировкойнагрузки, высокоскоростная выделенная линия (совместима со старыми клиентами), чрезвычайно низкая задержка, без проблем в часы пик, 4K видео загружается мгновенно
|
||||||
- Первый в мире VPN-сервис (айрпорт) на **протоколе QUIC**, теперь с более быстрыми протоколами семейства QUIC (лучшее сочетание с клиентом Clash Verge)
|
- Первый в мире VPN-сервис (айрпорт) на **протоколе QUIC**, теперь с более быстрыми протоколами семейства QUIC (лучшее сочетание с клиентом Clash Verge)
|
||||||
- Разблокировка потоковые сервисы и ChatGPT
|
- Разблокировка потоковые сервисы и ChatGPT
|
||||||
- Официальный сайт: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- Официальный сайт: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
|
||||||
|
|
||||||
### 🤖 [GPTKefu — AI-платформа умного обслуживания клиентов с глубокой интеграцией Crisp](https://gptkefu.com)
|
### 🤖 [GPTKefu — AI-платформа умного обслуживания клиентов с глубокой интеграцией Crisp](https://gptkefu.com)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clash-verge",
|
"name": "clash-verge",
|
||||||
"version": "2.5.6",
|
"version": "2.5.7",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky || true",
|
"prepare": "husky || true",
|
||||||
@@ -144,5 +144,5 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@12.5.1"
|
"packageManager": "pnpm@12.8.1"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+61
-61
@@ -7,153 +7,153 @@ importers:
|
|||||||
configDependencies: {}
|
configDependencies: {}
|
||||||
packageManagerDependencies:
|
packageManagerDependencies:
|
||||||
pnpm:
|
pnpm:
|
||||||
specifier: 12.5.1
|
specifier: 12.8.1
|
||||||
version: 12.5.1
|
version: 12.8.1
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@pnpm/exe.android-arm64@12.5.1':
|
'@pnpm/exe.android-arm64@12.8.1':
|
||||||
resolution: {integrity: sha512-6LGBmQuDzUmgpHSuy+haG0jrmkwFNa4EuShDZqK3cIBv4Wfb75CzjJmowkzr+iJg40vnBKMQ62t4Ko6mwsId7A==}
|
resolution: {integrity: sha512-siDxcidfz5eM6L2tJfik+i2bbUEw8UC7MZ3Yl2HYdRmqbdhHGAOQACtOOu6QVW4Jul4/w5wVKm+wM8ACtgh1Pg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@pnpm/exe.android-x64@12.5.1':
|
'@pnpm/exe.android-x64@12.8.1':
|
||||||
resolution: {integrity: sha512-091oCltP3Rx89yxL1Wh5rXkUXEyFzyxIzSHKRFDyDFlQkb8Ox8FaDcm+M8PNkMyqnLA+qeGOLzY7Rjj9izl1Ww==}
|
resolution: {integrity: sha512-0F/uqPRc3aN4vLHsa0f+6fTtmsigFQ9/yxEU43fionF//pNHEd5e97b3w/nKIgqYMCUQCJphmBRMA9Q8/wlo9Q==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@pnpm/exe.darwin-arm64@12.5.1':
|
'@pnpm/exe.darwin-arm64@12.8.1':
|
||||||
resolution: {integrity: sha512-r1vEMQPVjRexZMyL2HonxJoo3+nuB/+G+tg+f2PK6faRdXX1TDwevKXOxJAfqlPInTy6W/pm912+s+m0NcR4BQ==}
|
resolution: {integrity: sha512-/rwavvMQJsl2RIxOHBnDF+4Gk+fhQFAY4M3PQZoKskJOEnaJcygG9p1xby6wcQcbS4d9dIubv09CQhufTgfmpw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@pnpm/exe.darwin-x64@12.5.1':
|
'@pnpm/exe.darwin-x64@12.8.1':
|
||||||
resolution: {integrity: sha512-YHwI1g2B+Y2cAEylOR31r781GWijdJL7Gy7TEn/ZpZ5v/Cuwp5/Pz0EFCgo0M2MKLafAbL/laUMGvOpAdnerAw==}
|
resolution: {integrity: sha512-htYt2gN7zqJKLhC99Ft6EUiO7myjZAZXfmGCTJUL1v+o7vE9hZdE1+fAkk4Oj1ZHNRti6b2woOxEkRkAusi8OQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@pnpm/exe.freebsd-x64@12.5.1':
|
'@pnpm/exe.freebsd-x64@12.8.1':
|
||||||
resolution: {integrity: sha512-sFUMHiYFs6q5syFwgaVppzhQSmqnXoJIz/YwTXIOXTDE76ndIpTRpDGAnBCBKjsaEBnqjJA/2l6hpJcNDNoMiA==}
|
resolution: {integrity: sha512-PB5BULNgytxvExoOXUUeseS/DcpPENs+cg3iA6xHHeaLT4ctEGKSGXEbuj7USeqvo8JBpAx039hivnbzGqDwnA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@pnpm/exe.linux-arm64-musl@12.5.1':
|
'@pnpm/exe.linux-arm64-musl@12.8.1':
|
||||||
resolution: {integrity: sha512-zupuxYZBuBEGjUz805/4/Asq01UNziFADANt8yp+LdUjU9bbMa3xY78Bx1PsGDqBy7aiad4sdUMK8ZxH4n4gmQ==}
|
resolution: {integrity: sha512-kKeyC/ArjrgdciQRBrOL0j9HtOI4gDRgoyP+eJ1CQKyadpKlf/DhDDyspXe07R3B9KagTVLUF2nlt6Dr5quFIg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
libc: [musl]
|
||||||
|
|
||||||
'@pnpm/exe.linux-arm64@12.5.1':
|
'@pnpm/exe.linux-arm64@12.8.1':
|
||||||
resolution: {integrity: sha512-6hbMWW2/eQo1b5wvQPe/ndLHVTH88Rav6N+ffD4/h6IuFMjWCgasFYYsFv0GrvpqREAx3SwmZSvli+0NFXqbxA==}
|
resolution: {integrity: sha512-q4s9a9X2O3N9aeUFooW24orNrxvu20+jyVUFR5RanPCqOKKPBrgs2iywMkBBx1aXkkzdWT54/mfz8Be8sJlWEw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@pnpm/exe.linux-ppc64@12.5.1':
|
'@pnpm/exe.linux-ppc64@12.8.1':
|
||||||
resolution: {integrity: sha512-Gg3maDzaE/ZFMV9HIx/BwMN0Y6QbEs13URfxmiYHtKjjLAs5wEQZRMUP87YNLYO7cNaEfbM8GRbS9vPosyD9Gw==}
|
resolution: {integrity: sha512-F7XSjKJthwCh/L6abZiMpAfo2Cm61SZIT3e4dfgiIjESndlWaXCnfLKngSgZ/SEMsdmHT6dud3+kWIB3tw0/xQ==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@pnpm/exe.linux-riscv64@12.5.1':
|
'@pnpm/exe.linux-riscv64@12.8.1':
|
||||||
resolution: {integrity: sha512-6fgWxXYMBMsWQ8DAiRevscX4QZQjwh+FsyCj8ZOk8pMXvqeq84MqBLCmS6KckvnbdqJ+HlSVQ7fs/kd0ldwfhA==}
|
resolution: {integrity: sha512-z1ecpIK/ZY08Unk69KWWE9867oaKUytGUjrHnBoGFAAhsK+q+0cfvBH+f5fWobJ7FX97leMlLO+gkJolddM45Q==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@pnpm/exe.linux-s390x@12.5.1':
|
'@pnpm/exe.linux-s390x@12.8.1':
|
||||||
resolution: {integrity: sha512-nzMZruRvxDhEfYUhzu+7EmM39+82Dgagc/6hPFPqGqzXNGcIG0anuxbUxfeNtI64SHt91KuuYUmCB/inlM+Pag==}
|
resolution: {integrity: sha512-KU6tnrBfu4uKXTq6N5qJwSm8FSrs9Wc8b5AUEsHK9bRXwNdsZ1/lRxG1++X29SKRW9OSNuDSjxASv5mAvGo1gA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@pnpm/exe.linux-x64-musl@12.5.1':
|
'@pnpm/exe.linux-x64-musl@12.8.1':
|
||||||
resolution: {integrity: sha512-kHCbegdTNHpzmPtUD4S5fqkVkqgdQR47spF9p2VPP3dIIkZl6Ytk8w0vhlAsAGgge8FmucfwX+vvPKgm0NtOCQ==}
|
resolution: {integrity: sha512-eUE8BWJkDr2tJb/yrk0yVnszlmNqFarVxUlqiZ9BAkct28Nq/5g2H0tvMDmPA7fAQW3STNj+omJPPRVT+4s5sQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
libc: [musl]
|
||||||
|
|
||||||
'@pnpm/exe.linux-x64@12.5.1':
|
'@pnpm/exe.linux-x64@12.8.1':
|
||||||
resolution: {integrity: sha512-3PkUBYo5z4dgtlnTNIFj7QGpcDUAuqXz9WGVigPDCeccEnhGiRkWmA5102TmYJHtwJP3LfmE+ZF9PGeWhn8p9Q==}
|
resolution: {integrity: sha512-8bDZ0lZlCdi2rvnFul7EYgcC7zKeWSe76y8JV2oXobaS8p9i9d6PSf6LgLtTM0fI7R9Oh4eLCbveXyNDMmvZ+g==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@pnpm/exe.win32-arm64@12.5.1':
|
'@pnpm/exe.win32-arm64@12.8.1':
|
||||||
resolution: {integrity: sha512-49NvjZIXHly56/PLoEDD7VphbO4N8dwMXoApElDFCpVGDNGeKlwlib1tXtnpTF6i2/XIsAj7GgatHB5KHXgBnA==}
|
resolution: {integrity: sha512-MsT0dlrRxnCRCHCaosNbhWpEiAFnFuMEu3KuDJDU41BXgTwiINxU8goloUSUDejWZUqKaUqNC/qUTihl9nFtqg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@pnpm/exe.win32-x64@12.5.1':
|
'@pnpm/exe.win32-x64@12.8.1':
|
||||||
resolution: {integrity: sha512-ePUmQFPAPJFNMwg1lelDx2PdjHqYRiF0yfg5e6qeDbPNOu97QNo557Ru/SxmCrmt8ydQWNuZXWpdEp019md5vw==}
|
resolution: {integrity: sha512-SWtPe0PsbTTk//gJND10tMdOfCYjrkq5+qV49hzVhY7xz2iJ339Rc+xwASlcvbwTfrvH39YNqpKYibD+CRGLwA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
pnpm@12.5.1:
|
pnpm@12.8.1:
|
||||||
resolution: {integrity: sha512-4/MFvHhKK8ifWtO2E4iJRw+ujSr182thIW7JHCw9ZAiXdfneOKrDMQROpA8kXLDVZmOS399lgk4ZB+9qLGLeXw==}
|
resolution: {integrity: sha512-9kupB1B/XOr+BsjTjmBS0BeURFgOwSed3Vv8EctIqoomRLZlmOB+dh2oSHKp/FfV+QK4f6SdAkGY1VhhKqu+RQ==}
|
||||||
engines: {node: '>=18.*'}
|
engines: {node: '>=18.*'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@pnpm/exe.android-arm64@12.5.1':
|
'@pnpm/exe.android-arm64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.android-x64@12.5.1':
|
'@pnpm/exe.android-x64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.darwin-arm64@12.5.1':
|
'@pnpm/exe.darwin-arm64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.darwin-x64@12.5.1':
|
'@pnpm/exe.darwin-x64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.freebsd-x64@12.5.1':
|
'@pnpm/exe.freebsd-x64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-arm64-musl@12.5.1':
|
'@pnpm/exe.linux-arm64-musl@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-arm64@12.5.1':
|
'@pnpm/exe.linux-arm64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-ppc64@12.5.1':
|
'@pnpm/exe.linux-ppc64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-riscv64@12.5.1':
|
'@pnpm/exe.linux-riscv64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-s390x@12.5.1':
|
'@pnpm/exe.linux-s390x@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-x64-musl@12.5.1':
|
'@pnpm/exe.linux-x64-musl@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.linux-x64@12.5.1':
|
'@pnpm/exe.linux-x64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.win32-arm64@12.5.1':
|
'@pnpm/exe.win32-arm64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@pnpm/exe.win32-x64@12.5.1':
|
'@pnpm/exe.win32-x64@12.8.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
pnpm@12.5.1:
|
pnpm@12.8.1:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@pnpm/exe.android-arm64': 12.5.1
|
'@pnpm/exe.android-arm64': 12.8.1
|
||||||
'@pnpm/exe.android-x64': 12.5.1
|
'@pnpm/exe.android-x64': 12.8.1
|
||||||
'@pnpm/exe.darwin-arm64': 12.5.1
|
'@pnpm/exe.darwin-arm64': 12.8.1
|
||||||
'@pnpm/exe.darwin-x64': 12.5.1
|
'@pnpm/exe.darwin-x64': 12.8.1
|
||||||
'@pnpm/exe.freebsd-x64': 12.5.1
|
'@pnpm/exe.freebsd-x64': 12.8.1
|
||||||
'@pnpm/exe.linux-arm64': 12.5.1
|
'@pnpm/exe.linux-arm64': 12.8.1
|
||||||
'@pnpm/exe.linux-arm64-musl': 12.5.1
|
'@pnpm/exe.linux-arm64-musl': 12.8.1
|
||||||
'@pnpm/exe.linux-ppc64': 12.5.1
|
'@pnpm/exe.linux-ppc64': 12.8.1
|
||||||
'@pnpm/exe.linux-riscv64': 12.5.1
|
'@pnpm/exe.linux-riscv64': 12.8.1
|
||||||
'@pnpm/exe.linux-s390x': 12.5.1
|
'@pnpm/exe.linux-s390x': 12.8.1
|
||||||
'@pnpm/exe.linux-x64': 12.5.1
|
'@pnpm/exe.linux-x64': 12.8.1
|
||||||
'@pnpm/exe.linux-x64-musl': 12.5.1
|
'@pnpm/exe.linux-x64-musl': 12.8.1
|
||||||
'@pnpm/exe.win32-arm64': 12.5.1
|
'@pnpm/exe.win32-arm64': 12.8.1
|
||||||
'@pnpm/exe.win32-x64': 12.5.1
|
'@pnpm/exe.win32-x64': 12.8.1
|
||||||
|
|
||||||
---
|
---
|
||||||
lockfileVersion: '9.0'
|
lockfileVersion: '9.0'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.5.6"
|
version = "2.5.7"
|
||||||
description = "clash verge"
|
description = "clash verge"
|
||||||
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
@@ -99,7 +99,7 @@ tracing = { workspace = true }
|
|||||||
tauri-plugin-devtools = { version = "2.2.1", optional = true }
|
tauri-plugin-devtools = { version = "2.2.1", optional = true }
|
||||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo", branch = "main" }
|
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo", branch = "main" }
|
||||||
async-trait = "0.1.92"
|
async-trait = "0.1.92"
|
||||||
clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.7.4", version = "2.7.4", features = [
|
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 = [
|
||||||
"client",
|
"client",
|
||||||
] }
|
] }
|
||||||
arc-swap = "1.9.2"
|
arc-swap = "1.9.2"
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ pub async fn continue_with_sidecar() -> CmdResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn take_service_fallback_notice() -> bool {
|
pub fn take_service_fallback_notice() -> Option<crate::core::service::ServiceFallbackNotice> {
|
||||||
crate::core::service::take_service_fallback_notice()
|
crate::core::service::take_service_fallback_notice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ impl DnsOverrideState {
|
|||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct ProfileDnsSettings {
|
pub struct ProfileDnsSettings {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
// Force-enable confirmation is valid only for the current app session.
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(skip)]
|
|
||||||
pub confirmation: Option<String>,
|
pub confirmation: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +194,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dns_override_confirmation_expires_on_restart() -> Result<()> {
|
fn dns_override_confirmation_survives_restart_only_for_the_same_source() -> Result<()> {
|
||||||
let source = Some("provider-dns".into());
|
let source = Some("provider-dns".into());
|
||||||
let confirmed = IVerge {
|
let confirmed = IVerge {
|
||||||
profile_dns_settings: [(
|
profile_dns_settings: [(
|
||||||
@@ -208,15 +207,22 @@ mod tests {
|
|||||||
.into(),
|
.into(),
|
||||||
..IVerge::default()
|
..IVerge::default()
|
||||||
};
|
};
|
||||||
let settings = confirmed.dns_settings_for("one");
|
let saved = serde_yaml_ng::to_string(&confirmed)?;
|
||||||
assert!(DnsOverrideState::new("one", source.clone(), settings.enabled, settings.confirmation).enabled);
|
let mut restarted: IVerge = serde_yaml_ng::from_str(&saved)?;
|
||||||
for saved in [
|
let settings = restarted.dns_settings_for("one");
|
||||||
serde_yaml_ng::to_string(&confirmed)?,
|
let state = DnsOverrideState::new("one", source.clone(), settings.enabled, settings.confirmation);
|
||||||
"enable_dns_settings: true\ndns_override_confirmation: provider-dns".to_owned(),
|
assert!(state.enabled);
|
||||||
|
assert!(!state.apply_to(&mut restarted));
|
||||||
|
for (saved, source) in [
|
||||||
|
(saved, Some("updated".into())),
|
||||||
|
(
|
||||||
|
"enable_dns_settings: true\ndns_override_confirmation: provider-dns".to_owned(),
|
||||||
|
source,
|
||||||
|
),
|
||||||
] {
|
] {
|
||||||
let mut restarted: IVerge = serde_yaml_ng::from_str(&saved)?;
|
let mut restarted: IVerge = serde_yaml_ng::from_str(&saved)?;
|
||||||
let settings = restarted.dns_settings_for("one");
|
let settings = restarted.dns_settings_for("one");
|
||||||
let state = DnsOverrideState::new("one", source.clone(), settings.enabled, settings.confirmation);
|
let state = DnsOverrideState::new("one", source, settings.enabled, settings.confirmation);
|
||||||
assert!(!state.enabled, "a previous session must not bypass startup protection");
|
assert!(!state.enabled, "a previous session must not bypass startup protection");
|
||||||
assert!(state.apply_to(&mut restarted));
|
assert!(state.apply_to(&mut restarted));
|
||||||
assert!(!restarted.dns_settings_for("one").enabled);
|
assert!(!restarted.dns_settings_for("one").enabled);
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ impl CoreManager {
|
|||||||
SERVICE_MANAGER.withdraw_sidecar_allowance();
|
SERVICE_MANAGER.withdraw_sidecar_allowance();
|
||||||
self.rollback_failed_start().await;
|
self.rollback_failed_start().await;
|
||||||
} else {
|
} else {
|
||||||
crate::core::service::notify_service_fallback();
|
crate::core::service::notify_service_fallback(&reason);
|
||||||
}
|
}
|
||||||
result.map_err(|error| error.context(format!("Service failure before Sidecar startup: {reason}")))
|
result.map_err(|error| error.context(format!("Service failure before Sidecar startup: {reason}")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub use env::FakeEnv;
|
|||||||
pub use env::{RealEnv, RunStateEnv};
|
pub use env::{RealEnv, RunStateEnv};
|
||||||
pub use health::{PendingAction, RunState, RunStateView, ServiceHealth};
|
pub use health::{PendingAction, RunState, RunStateView, ServiceHealth};
|
||||||
pub use owner::{OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch};
|
pub use owner::{OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch};
|
||||||
pub use probe::{ServiceVersionCheck, ServiceVersionReply, classify_service_version_reply};
|
pub use probe::{CORE_REJECTED_PREFIX, ServiceVersionCheck, ServiceVersionReply, classify_service_version_reply};
|
||||||
|
|
||||||
use crate::core::manager::RunningMode;
|
use crate::core::manager::RunningMode;
|
||||||
use health::StoredService;
|
use health::StoredService;
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ pub enum ServiceVersionCheck {
|
|||||||
CoreUnavailable(String),
|
CoreUnavailable(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Leads the Unavailable reason when the Service refused the approved core itself.
|
||||||
|
pub const CORE_REJECTED_PREFIX: &str = "approved core was rejected: ";
|
||||||
|
|
||||||
/// What a live probe of the currently-installed Service told us.
|
/// What a live probe of the currently-installed Service told us.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CurrentServiceProbe {
|
pub enum CurrentServiceProbe {
|
||||||
@@ -47,7 +50,7 @@ pub fn classify_service_version_reply(reply: &ServiceVersionReply) -> ServiceVer
|
|||||||
return match &reply.core {
|
return match &reply.core {
|
||||||
Some(clash_verge_service_ipc::CoreAvailability::Ready) => ServiceVersionCheck::Ready,
|
Some(clash_verge_service_ipc::CoreAvailability::Ready) => ServiceVersionCheck::Ready,
|
||||||
Some(clash_verge_service_ipc::CoreAvailability::Rejected { reason }) => {
|
Some(clash_verge_service_ipc::CoreAvailability::Rejected { reason }) => {
|
||||||
ServiceVersionCheck::CoreUnavailable(format!("approved core was rejected: {reason}"))
|
ServiceVersionCheck::CoreUnavailable(format!("{CORE_REJECTED_PREFIX}{reason}"))
|
||||||
}
|
}
|
||||||
_ => ServiceVersionCheck::CoreUnavailable(
|
_ => ServiceVersionCheck::CoreUnavailable(
|
||||||
"the selected approved core is missing or does not match; reinstall the service to repair it".into(),
|
"the selected approved core is missing or does not match; reinstall the service to repair it".into(),
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use crate::{
|
|||||||
owner_identity::current_owner_credentials,
|
owner_identity::current_owner_credentials,
|
||||||
proxy_control,
|
proxy_control,
|
||||||
runstate::{
|
runstate::{
|
||||||
OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch, PendingAction, RUN_STATE, ReadyWaitError,
|
CORE_REJECTED_PREFIX, OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch, PendingAction, RUN_STATE,
|
||||||
RunState, RunStateEnv, RunStateStore, ServiceHealth,
|
ReadyWaitError, RunState, RunStateEnv, RunStateStore, ServiceHealth,
|
||||||
},
|
},
|
||||||
runtime_bundle::{RemoteProviderRef, collect_runtime_bundle, remote_providers_of},
|
runtime_bundle::{RemoteProviderRef, collect_runtime_bundle, remote_providers_of},
|
||||||
tray::Tray,
|
tray::Tray,
|
||||||
@@ -39,18 +39,31 @@ use std::{
|
|||||||
|
|
||||||
static OWNER_MONITOR_GENERATION: AtomicU64 = AtomicU64::new(0);
|
static OWNER_MONITOR_GENERATION: AtomicU64 = AtomicU64::new(0);
|
||||||
static ACTIVE_SERVICE_SESSION: Lazy<Mutex<Option<ActiveServiceSession>>> = Lazy::new(|| Mutex::new(None));
|
static ACTIVE_SERVICE_SESSION: Lazy<Mutex<Option<ActiveServiceSession>>> = Lazy::new(|| Mutex::new(None));
|
||||||
static PENDING_SERVICE_FALLBACK_NOTICE: AtomicBool = AtomicBool::new(false);
|
static PENDING_SERVICE_FALLBACK_NOTICE: Mutex<Option<String>> = Mutex::new(None);
|
||||||
static PENDING_SERVICE_REPAIR_NOTICE: AtomicBool = AtomicBool::new(false);
|
static PENDING_SERVICE_REPAIR_NOTICE: AtomicBool = AtomicBool::new(false);
|
||||||
static PENDING_SERVICE_OWNER_NOTICE: Mutex<Option<String>> = Mutex::new(None);
|
static PENDING_SERVICE_OWNER_NOTICE: Mutex<Option<String>> = Mutex::new(None);
|
||||||
|
|
||||||
|
/// Why the Service was unavailable when the core fell back to Sidecar.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
|
||||||
|
#[serde(tag = "kind", content = "reason", rename_all = "camelCase")]
|
||||||
|
pub enum ServiceFallbackNotice {
|
||||||
|
Unavailable,
|
||||||
|
CoreRejected(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub(crate) fn notify_service_fallback() {
|
pub(crate) fn notify_service_fallback(reason: &str) {
|
||||||
PENDING_SERVICE_FALLBACK_NOTICE.store(true, Ordering::Relaxed);
|
*PENDING_SERVICE_FALLBACK_NOTICE.lock() = Some(reason.to_owned());
|
||||||
Handle::notice_message("service_core::sidecar_fallback", "");
|
Handle::notice_message("service_core::sidecar_fallback", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_service_fallback_notice() -> bool {
|
pub(crate) fn take_service_fallback_notice() -> Option<ServiceFallbackNotice> {
|
||||||
PENDING_SERVICE_FALLBACK_NOTICE.swap(false, Ordering::Relaxed)
|
let reason = PENDING_SERVICE_FALLBACK_NOTICE.lock().take()?;
|
||||||
|
Some(if reason.starts_with(CORE_REJECTED_PREFIX) {
|
||||||
|
ServiceFallbackNotice::CoreRejected(reason)
|
||||||
|
} else {
|
||||||
|
ServiceFallbackNotice::Unavailable
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_service_repair_notice() -> bool {
|
pub(crate) fn take_service_repair_notice() -> bool {
|
||||||
@@ -833,7 +846,10 @@ fn record_service_start_refusal<E: RunStateEnv>(
|
|||||||
store: &RunStateStore<E>,
|
store: &RunStateStore<E>,
|
||||||
refusal: ServiceStartRefusal,
|
refusal: ServiceStartRefusal,
|
||||||
) -> anyhow::Error {
|
) -> anyhow::Error {
|
||||||
if store.state().mode == crate::core::manager::RunningMode::NotRunning {
|
// A proxy clear failure is about the system network settings; repairing the service cannot fix it.
|
||||||
|
if store.state().mode == crate::core::manager::RunningMode::NotRunning
|
||||||
|
&& refusal.code != ServiceErrorCode::ProxyClearFailed as u16
|
||||||
|
{
|
||||||
store.observe(ServiceHealth::Unavailable(refusal.to_string()));
|
store.observe(ServiceHealth::Unavailable(refusal.to_string()));
|
||||||
}
|
}
|
||||||
refusal.into()
|
refusal.into()
|
||||||
@@ -916,7 +932,7 @@ pub(super) async fn start_with_existing_service(config_file: &Path) -> Result<()
|
|||||||
// PAC follows the Running Mode; the caller opens it via `core_started(Service)`.
|
// PAC follows the Running Mode; the caller opens it via `core_started(Service)`.
|
||||||
start_owner_monitor();
|
start_owner_monitor();
|
||||||
tracing::Span::current().record("outcome", "started");
|
tracing::Span::current().record("outcome", "started");
|
||||||
PENDING_SERVICE_FALLBACK_NOTICE.store(false, Ordering::Relaxed);
|
PENDING_SERVICE_FALLBACK_NOTICE.lock().take();
|
||||||
PENDING_SERVICE_REPAIR_NOTICE.store(false, Ordering::Relaxed);
|
PENDING_SERVICE_REPAIR_NOTICE.store(false, Ordering::Relaxed);
|
||||||
PENDING_SERVICE_OWNER_NOTICE.lock().take();
|
PENDING_SERVICE_OWNER_NOTICE.lock().take();
|
||||||
logging!(
|
logging!(
|
||||||
@@ -2312,6 +2328,23 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn proxy_clear_refusal_does_not_ask_for_service_repair() {
|
||||||
|
let store = fake_store();
|
||||||
|
store.observe(ServiceHealth::Ready);
|
||||||
|
let _ = super::record_service_start_refusal(
|
||||||
|
&store,
|
||||||
|
super::ServiceStartRefusal {
|
||||||
|
code: clash_verge_service_ipc::ServiceErrorCode::ProxyClearFailed as u16,
|
||||||
|
core_path: "/development/service-core/verge-mihomo".into(),
|
||||||
|
message: "SystemConfiguration operation failed: lock preferences (status 3002)".into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(store.state().service_usable());
|
||||||
|
assert!(!store.state().service_needs_attention());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cached_readiness_is_false_while_a_service_operation_is_running() {
|
fn cached_readiness_is_false_while_a_service_operation_is_running() {
|
||||||
let store = fake_store();
|
let store = fake_store();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "2.5.6",
|
"version": "2.5.7",
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
|
|||||||
@@ -100,13 +100,18 @@ export const LayoutSidebar = (props: LayoutSidebarProps) => {
|
|||||||
const item = navItemMap.get(path)
|
const item = navItemMap.get(path)
|
||||||
if (!item) return null
|
if (!item) return null
|
||||||
|
|
||||||
|
// A registered sortable, even a disabled one, gets the drag-and-drop ARIA
|
||||||
|
// attributes, so screen readers announce every item as a disabled draggable.
|
||||||
|
if (!menuUnlocked) {
|
||||||
|
return (
|
||||||
|
<LayoutItem key={item.path} to={item.path} icon={item.icon}>
|
||||||
|
{t(item.label)}
|
||||||
|
</LayoutItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortableItem
|
<SortableItem key={item.path} id={item.path} index={index}>
|
||||||
key={item.path}
|
|
||||||
id={item.path}
|
|
||||||
index={index}
|
|
||||||
disabled={!menuUnlocked}
|
|
||||||
>
|
|
||||||
{(sortable) => (
|
{(sortable) => (
|
||||||
<LayoutItem to={item.path} icon={item.icon} sortable={sortable}>
|
<LayoutItem to={item.path} icon={item.icon} sortable={sortable}>
|
||||||
{t(item.label)}
|
{t(item.label)}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
type RunState,
|
type RunState,
|
||||||
getCoreStartupError,
|
getCoreStartupError,
|
||||||
takeDnsOverrideNotice,
|
takeDnsOverrideNotice,
|
||||||
|
takeServiceFallbackNotice,
|
||||||
takeServiceRepairNotice,
|
takeServiceRepairNotice,
|
||||||
} from '@/services/cmds'
|
} from '@/services/cmds'
|
||||||
import { subscribeVergeEvents } from '@/services/events'
|
import { subscribeVergeEvents } from '@/services/events'
|
||||||
@@ -31,13 +32,13 @@ vi.mock('@/services/cmds', () => ({
|
|||||||
getCoreStartupError: vi.fn().mockResolvedValue(null),
|
getCoreStartupError: vi.fn().mockResolvedValue(null),
|
||||||
takeDiscardedKeysNotice: vi.fn().mockResolvedValue(null),
|
takeDiscardedKeysNotice: vi.fn().mockResolvedValue(null),
|
||||||
takeDnsOverrideNotice: vi.fn().mockResolvedValue(false),
|
takeDnsOverrideNotice: vi.fn().mockResolvedValue(false),
|
||||||
takeServiceFallbackNotice: vi.fn().mockResolvedValue(false),
|
takeServiceFallbackNotice: vi.fn().mockResolvedValue(null),
|
||||||
takeServiceRepairNotice: vi.fn().mockResolvedValue(false),
|
takeServiceRepairNotice: vi.fn().mockResolvedValue(false),
|
||||||
takeServiceOwnerNotice: vi.fn().mockResolvedValue(null),
|
takeServiceOwnerNotice: vi.fn().mockResolvedValue(null),
|
||||||
}))
|
}))
|
||||||
vi.mock('@/services/service-request', () => ({ requestService: vi.fn() }))
|
vi.mock('@/services/service-request', () => ({ requestService: vi.fn() }))
|
||||||
vi.mock('@/services/notice-service', () => ({
|
vi.mock('@/services/notice-service', () => ({
|
||||||
showNotice: { info: vi.fn(), error: vi.fn() },
|
showNotice: { info: vi.fn(), error: vi.fn(), warning: vi.fn() },
|
||||||
}))
|
}))
|
||||||
vi.mock('@/services/query-client', () => ({
|
vi.mock('@/services/query-client', () => ({
|
||||||
revalidateQueries: vi.fn(),
|
revalidateQueries: vi.fn(),
|
||||||
@@ -184,3 +185,26 @@ it('offers service reinstallation for a startup path refusal even before listene
|
|||||||
reason: 'serviceLocationRefused',
|
reason: 'serviceLocationRefused',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('explains a startup core rejection instead of the generic fallback notice', async () => {
|
||||||
|
const reason =
|
||||||
|
'approved core was rejected: core path "C:\\" has an untrusted write ACE'
|
||||||
|
vi.mocked(takeServiceFallbackNotice)
|
||||||
|
.mockResolvedValueOnce({ kind: 'coreRejected', reason })
|
||||||
|
.mockResolvedValue(null)
|
||||||
|
|
||||||
|
useLayoutEvents(([status, message]) => {
|
||||||
|
handleNoticeMessage(status, message, (key) => key, vi.fn())
|
||||||
|
})
|
||||||
|
|
||||||
|
const [handlers, onSubscribed] = vi.mocked(subscribeVergeEvents).mock.calls[0]
|
||||||
|
onSubscribed?.()
|
||||||
|
handlers['verge://notice-message']?.(['service_core::sidecar_fallback', ''])
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||||
|
|
||||||
|
expect(showNotice.warning).toHaveBeenCalledExactlyOnceWith(
|
||||||
|
'settings.feedback.notifications.clashService.permissionFallback',
|
||||||
|
{ reason },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|||||||
@@ -117,8 +117,14 @@ export const handleNoticeMessage = (
|
|||||||
},
|
},
|
||||||
'service_core::sidecar_fallback': () => {
|
'service_core::sidecar_fallback': () => {
|
||||||
void takeServiceFallbackNotice()
|
void takeServiceFallbackNotice()
|
||||||
.then((pending) => {
|
.then((notice) => {
|
||||||
if (pending) {
|
if (notice?.kind === 'coreRejected') {
|
||||||
|
showNotice.warning(
|
||||||
|
'settings.feedback.notifications.clashService.permissionFallback',
|
||||||
|
{ reason: notice.reason },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
} else if (notice) {
|
||||||
showNotice.warning(
|
showNotice.warning(
|
||||||
'settings.feedback.notifications.clashService.sidecarFallback',
|
'settings.feedback.notifications.clashService.sidecarFallback',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -186,8 +186,12 @@ export async function takeDnsOverrideNotice() {
|
|||||||
return invoke<boolean>('take_dns_override_notice')
|
return invoke<boolean>('take_dns_override_notice')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ServiceFallbackNotice =
|
||||||
|
| { kind: 'unavailable' }
|
||||||
|
| { kind: 'coreRejected'; reason: string }
|
||||||
|
|
||||||
export async function takeServiceFallbackNotice() {
|
export async function takeServiceFallbackNotice() {
|
||||||
return invoke<boolean>('take_service_fallback_notice')
|
return invoke<ServiceFallbackNotice | null>('take_service_fallback_notice')
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreFailure {
|
export interface CoreFailure {
|
||||||
|
|||||||
Reference in New Issue
Block a user