Compare commits

..
8 Commits
Author SHA1 Message Date
wonfen ea509b8236 chore(deps): pin clash-verge-service-ipc to v2.7.6 2026-10-02 22:57:11 +08:00
wonfen 52d616302c fix(service): explain a startup core rejection instead of the generic fallback
When the startup probe finds the service refusing the approved core, the
app falls back to Sidecar with only the generic "could not start the
core" notice. The reason and repair guide appeared only after a
reinstall, which cannot fix a writable volume root (#8045).

Carry the fallback reason to the window and show the same permission
notice as a rejected installation when the core was refused.

Refs #8045
2026-10-02 10:38:09 +08:00
wonfen 8ddd99f226 chore: bump version v2.5.7 2026-09-30 22:07:17 +08:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> e0e97a920e chore(deps): update dependency pnpm to v12.8.1 (#8127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-30 06:27:19 +00:00
wonfen c4f9d65e07 fix(service): don't ask to repair the service when the proxy clear fails 2026-09-29 10:09:21 +08:00
wonfen 0c7e0c8535 fix(dns): persist DNS override confirmation across restarts
A confirmed override on a profile with provider DNS was turned off at
every startup; it now stays on until that profile's provider DNS changes.

Refs #7993
2026-09-28 13:09:09 +08:00
mrhard9090andClaude Opus 5.5 1638ab48d8 fix(layout): don't expose locked sidebar items as draggables (#8064)
While the menu order is locked, the sidebar items were still registered as
disabled sortables, so dnd-kit gave each nav button a draggable role
description, aria-disabled=true, aria-pressed and the drag instructions.
Screen readers announced every item as an unavailable draggable toggle.
Only wrap the items in SortableItem while reordering is unlocked.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 12:37:54 +00:00
❤是纱雾酱哟~ 5d7dc3aed9 chore(gh-aw): Bump gh-aw to version v0.89.21 (#8072)
Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2026-09-26 09:51:01 +00:00
31 changed files with 385 additions and 211 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
"features": {
"ghcr.io/devcontainers/features/node:2": {
"version": "24.21.0",
"pnpmVersion": "12.5.1"
"pnpmVersion": "12.8.1"
},
"ghcr.io/devcontainers/features/rust:1": {
"version": "1.98.1",
+26 -11
View File
@@ -5,10 +5,10 @@
"version": "v9.0.0",
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
},
"github/gh-aw-actions/setup@v0.89.15": {
"github/gh-aw-actions/setup@v0.89.21": {
"repo": "github/gh-aw-actions/setup",
"version": "v0.89.15",
"sha": "045beb2d14bda8d0c1f2e83b41527f63770d2855"
"version": "v0.89.21",
"sha": "924af5fdc64061cfbf66fb584c8b07e2ac230c60"
}
},
"containers": {
@@ -27,6 +27,11 @@
"digest": "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": {
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.28.13",
"digest": "sha256:61f12dcff38eb008b645d87a5541763452f409d9040eb243718764944167b1a2",
@@ -42,6 +47,11 @@
"digest": "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": {
"image": "ghcr.io/github/gh-aw-firewall/squid:0.28.13",
"digest": "sha256:58a8dc5be3fbafeef7da0532c38bd9047f86bf1b3c4cfd7d9b7d8d28e80a2b56",
@@ -57,20 +67,25 @@
"digest": "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": {
"image": "ghcr.io/github/gh-aw-mcpg:v0.4.21",
"digest": "sha256:f26f665840660581510746ed84f5fc706f4ca8c48833757dfb4d72d86587201e",
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.4.21@sha256:f26f665840660581510746ed84f5fc706f4ca8c48833757dfb4d72d86587201e"
"ghcr.io/github/gh-aw-firewall/squid:0.28.23": {
"image": "ghcr.io/github/gh-aw-firewall/squid:0.28.23",
"digest": "sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0",
"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": {
"image": "ghcr.io/github/gh-aw-node",
"digest": "sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e",
"pinned_image": "ghcr.io/github/gh-aw-node@sha256:bac2192f6374d6262116399b34fc5e143d576f82719e90a18261cae7480f4d4e"
},
"ghcr.io/github/github-mcp-server:v1.12.1": {
"image": "ghcr.io/github/github-mcp-server:v1.12.1",
"digest": "sha256:0ba840c46a237879c8300e7fddb0b6347f20e029ccb9cbe2ce4a943daa1ff560",
"pinned_image": "ghcr.io/github/github-mcp-server:v1.12.1@sha256:0ba840c46a237879c8300e7fddb0b6347f20e029ccb9cbe2ce4a943daa1ff560"
"ghcr.io/github/github-mcp-server:v1.12.2": {
"image": "ghcr.io/github/github-mcp-server:v1.12.2",
"digest": "sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6",
"pinned_image": "ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6"
}
}
}
+2 -2
View File
@@ -101,7 +101,7 @@ jobs:
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
@@ -580,7 +580,7 @@ jobs:
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
+1 -1
View File
@@ -31,6 +31,6 @@ jobs:
with:
persist-credentials: false
- 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:
version: v0.89.15
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -144,7 +144,7 @@ jobs:
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
@@ -691,7 +691,7 @@ jobs:
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
+1 -1
View File
@@ -90,7 +90,7 @@ jobs:
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
- [狗狗加速](https://cvr.dginv.click/#/register?code=oaxsAGo6)
Created at ${{ env.BUILDTIME }}.
EOF
+1 -1
View File
@@ -1,3 +1,3 @@
nodejs 24.21.0
pnpm 12.5.1
pnpm 12.8.1
rust 1.98.1
Generated
+4 -4
View File
@@ -1079,7 +1079,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "clash-verge"
version = "2.5.6"
version = "2.5.7"
dependencies = [
"aes-gcm",
"anyhow",
@@ -1223,8 +1223,8 @@ dependencies = [
[[package]]
name = "clash_verge_service_ipc"
version = "2.7.4"
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.7.4#b4f66bd5a365875562a622065d189e3514654b7f"
version = "2.7.6"
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.7.6#b2a7427d6681c8d3780ab83a73f4dc21da2f22d6"
dependencies = [
"anyhow",
"kode-bridge",
@@ -6922,7 +6922,7 @@ dependencies = [
[[package]]
name = "sysproxy"
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 = [
"iptools",
"log",
+17 -13
View File
@@ -1,31 +1,35 @@
## v2.5.6
## v2.5.7
<details>
<summary><strong> 🐞 修复问题 </strong></summary>
- 修复「代理集合」「规则集合」订阅响应较慢时更新误报失败、且不显示真实失败原因的问题
- 修复读屏软件将普通模式下的侧边栏导航项播报为不可用的可拖拽控件的问题
- 修复订阅包含自定义 DNS 时,确认开启的 DNS 覆写在重启应用后被自动关闭的问题
**🖥️ Windows**
- 修复 Windows 部分未安装服务的用户以普通权限运行时,内核无法启动的问题
- 修复 Windows 系统隔离权限被误判,导致服务模式和 TUN 无法使用的问题
- 修复 Windows 旧版服务状态残留导致无法重装的问题,自动备份可识别的残留并恢复安装
- 修复 Windows 服务已停止时,启动要等约两分钟才显示窗口的问题
- 优化 Windows 服务安全检查失败提示:用易懂的文字说明原因,并提供修复文档链接
- 修复 Windows 系统盘根目录的删除权限被误判,导致服务模式和 TUN 无法使用的问题
- 修复 Windows 部分系统安装服务失败,提示「program not found」的问题
**🍎 macOS**
- macOS 修复编辑规则时「规则内容」输入的首字母被自动转为大写的问题
- macOS 修复残留的服务进程导致内核无法启动、「继续使用 Sidecar」失败且无法修复的问题
- macOS 修复部分账户安装或修复服务时提示无法解析用户组而失败的问题
- macOS 优化用户目录在外置磁盘时服务拒绝启动内核的提示:说明原因并给出修复命令
- macOS 修复服务模式内核意外停止后,系统代理仍指向失效端口导致无法上网的问题
- macOS 修复启动或重启应用时偶发内核启动失败,并误提示「需要更新系统服务」的问题
- macOS 修复 VPN 接管网络或开机网络未就绪时的问题:服务模式内核无法启动、TUN 不可用、系统代理状态读取报错
- macOS 修复用 `ipconfig set` 手动配置网卡后无法设置系统代理的问题
**🍎/🐧 macOS/Linux**
- 修复 macOS/Linux 服务模式停止或重启内核时直接强制结束的问题:内核来不及正常退出、最后的日志丢失
</details>
<details>
<summary><strong> 🚀 优化改进 </strong></summary>
- 优化内核启动失败和服务模式内核意外停止的提示:显示具体原因,并在窗口恢复后提示尚未解决的错误
- 优化服务模式的问题排查:服务自身的运行日志会保存到文件,便于追查内核被停止的原因
**🖥️ Windows**
- 优化 Windows 服务安全检查未通过时的启动提示:不再只显示「服务无法启动内核」,直接说明原因并提供修复文档链接
</details>
+33
View File
@@ -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
<details>
@@ -34,6 +66,7 @@
- 扩展配置或脚本写入由应用设置接管的字段时,弹出提示并在扩展日志中记录该值已被丢弃
</details>
## v2.5.4
<details>
+3 -3
View File
@@ -51,11 +51,11 @@ Join [@clash_verge_rev](https://t.me/clash_verge_re) for update announcements.
## 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**.
🎁 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:**
@@ -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)
- 🎬 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)
+3 -3
View File
@@ -51,17 +51,17 @@ Consulta la [documentación del proyecto](https://clash-verge-rev.github.io/) pa
## 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.
- 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)
- 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
- 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)
- 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)
+3 -3
View File
@@ -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` (محدود به ۵۰۰ بار استفاده)
- بسته تخفیف‌دار از ۱۵.۸ ین در ماه برای ۱۶۰ گیگابایت، به علاوه ۲۰٪ تخفیف اضافی برای صورتحساب سالانه
- توسط یک تیم خارجی با خدمات قابل اعتماد و تا 50٪ سهم درآمد اداره می‌شود
- کلاسترهای متعادل بار با مسیرهای اختصاصی پرسرعت (سازگار با کلاینت‌های قدیمی)، تأخیر فوق‌العاده کم، پخش روان 4K
- اولین ارائه‌دهنده جهانی با **پروتکل QUIC**، اکنون با پروتکل‌های سریع‌تر خانواده QUIC (بهترین ترکیب با کلاینت Clash Verge)
- پشتیبانی از سرویس‌های استریم و دسترسی به ChatGPT
- وبسایت رسمی: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
- وبسایت رسمی: [https://狗狗加速.com](https://cvr.dginv.click/#/register?code=oaxsAGo6)
### 🤖 [GPTKefu — پلتفرم خدمات مشتری هوشمند مبتنی بر هوش مصنوعی با ادغام عمیق Crisp](https://gptkefu.com)
+3 -3
View File
@@ -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 プロトコル対応を備えた高性能海外ネットワークサービス。
- 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 名)
- 月額 15.8 元で 160 GB を利用できるプラン、年額契約ならさらに 20% オフ
- 海外チーム運営による高信頼サービス、収益シェアは最大 50%
- 負荷分散クラスタと高速専用回線(旧クライアント互換)、極低レイテンシで 4K も快適
- 世界初の **QUIC プロトコル**対応。より高速な QUIC 系プロトコルを提供(Clash Verge クライアントとの相性抜群)
- ストリーミングおよび 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)
+3 -3
View File
@@ -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 프로토콜 지원을 갖춘 고성능 해외 네트워크 서비스
- 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회)
- 월 15.8위안부터 160GB 제공, 연간 결제 시 추가 20% 할인
- 해외 팀 운영, 높은 신뢰성, 최대 50% 커미션
- 로드밸런싱 클러스터, 고속 전용 회선(구 클라이언트 호환), 매우 낮은 지연, 4K도 쾌적
- 세계 최초 **QUIC 프로토콜** 지원, 더 빠른 QUIC 계열 프로토콜 제공 (Clash Verge 클라이언트와 최적의 궁합)
- 스트리밍 및 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)
+3 -3
View File
@@ -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.
- Зарегистрируйтесь по эксклюзивной ссылке 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 штук)
- Специальный тарифный план всего за 15,8 юаней в месяц, 160 Гб трафика, скидка 20% при оплате за год
- Команда за рубежом, без риска побега, до 50% кэшбэка
- Архитектура с балансировкойнагрузки, высокоскоростная выделенная линия (совместима со старыми клиентами), чрезвычайно низкая задержка, без проблем в часы пик, 4K видео загружается мгновенно
- Первый в мире VPN-сервис (айрпорт) на **протоколе QUIC**, теперь с более быстрыми протоколами семейства QUIC (лучшее сочетание с клиентом Clash Verge)
- Разблокировка потоковые сервисы и 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)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "clash-verge",
"version": "2.5.6",
"version": "2.5.7",
"license": "GPL-3.0-only",
"scripts": {
"prepare": "husky || true",
@@ -144,5 +144,5 @@
]
},
"type": "module",
"packageManager": "pnpm@12.5.1"
"packageManager": "pnpm@12.8.1"
}
+61 -61
View File
@@ -7,153 +7,153 @@ importers:
configDependencies: {}
packageManagerDependencies:
pnpm:
specifier: 12.5.1
version: 12.5.1
specifier: 12.8.1
version: 12.8.1
packages:
'@pnpm/exe.android-arm64@12.5.1':
resolution: {integrity: sha512-6LGBmQuDzUmgpHSuy+haG0jrmkwFNa4EuShDZqK3cIBv4Wfb75CzjJmowkzr+iJg40vnBKMQ62t4Ko6mwsId7A==}
'@pnpm/exe.android-arm64@12.8.1':
resolution: {integrity: sha512-siDxcidfz5eM6L2tJfik+i2bbUEw8UC7MZ3Yl2HYdRmqbdhHGAOQACtOOu6QVW4Jul4/w5wVKm+wM8ACtgh1Pg==}
cpu: [arm64]
os: [android]
'@pnpm/exe.android-x64@12.5.1':
resolution: {integrity: sha512-091oCltP3Rx89yxL1Wh5rXkUXEyFzyxIzSHKRFDyDFlQkb8Ox8FaDcm+M8PNkMyqnLA+qeGOLzY7Rjj9izl1Ww==}
'@pnpm/exe.android-x64@12.8.1':
resolution: {integrity: sha512-0F/uqPRc3aN4vLHsa0f+6fTtmsigFQ9/yxEU43fionF//pNHEd5e97b3w/nKIgqYMCUQCJphmBRMA9Q8/wlo9Q==}
cpu: [x64]
os: [android]
'@pnpm/exe.darwin-arm64@12.5.1':
resolution: {integrity: sha512-r1vEMQPVjRexZMyL2HonxJoo3+nuB/+G+tg+f2PK6faRdXX1TDwevKXOxJAfqlPInTy6W/pm912+s+m0NcR4BQ==}
'@pnpm/exe.darwin-arm64@12.8.1':
resolution: {integrity: sha512-/rwavvMQJsl2RIxOHBnDF+4Gk+fhQFAY4M3PQZoKskJOEnaJcygG9p1xby6wcQcbS4d9dIubv09CQhufTgfmpw==}
cpu: [arm64]
os: [darwin]
'@pnpm/exe.darwin-x64@12.5.1':
resolution: {integrity: sha512-YHwI1g2B+Y2cAEylOR31r781GWijdJL7Gy7TEn/ZpZ5v/Cuwp5/Pz0EFCgo0M2MKLafAbL/laUMGvOpAdnerAw==}
'@pnpm/exe.darwin-x64@12.8.1':
resolution: {integrity: sha512-htYt2gN7zqJKLhC99Ft6EUiO7myjZAZXfmGCTJUL1v+o7vE9hZdE1+fAkk4Oj1ZHNRti6b2woOxEkRkAusi8OQ==}
cpu: [x64]
os: [darwin]
'@pnpm/exe.freebsd-x64@12.5.1':
resolution: {integrity: sha512-sFUMHiYFs6q5syFwgaVppzhQSmqnXoJIz/YwTXIOXTDE76ndIpTRpDGAnBCBKjsaEBnqjJA/2l6hpJcNDNoMiA==}
'@pnpm/exe.freebsd-x64@12.8.1':
resolution: {integrity: sha512-PB5BULNgytxvExoOXUUeseS/DcpPENs+cg3iA6xHHeaLT4ctEGKSGXEbuj7USeqvo8JBpAx039hivnbzGqDwnA==}
cpu: [x64]
os: [freebsd]
'@pnpm/exe.linux-arm64-musl@12.5.1':
resolution: {integrity: sha512-zupuxYZBuBEGjUz805/4/Asq01UNziFADANt8yp+LdUjU9bbMa3xY78Bx1PsGDqBy7aiad4sdUMK8ZxH4n4gmQ==}
'@pnpm/exe.linux-arm64-musl@12.8.1':
resolution: {integrity: sha512-kKeyC/ArjrgdciQRBrOL0j9HtOI4gDRgoyP+eJ1CQKyadpKlf/DhDDyspXe07R3B9KagTVLUF2nlt6Dr5quFIg==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@pnpm/exe.linux-arm64@12.5.1':
resolution: {integrity: sha512-6hbMWW2/eQo1b5wvQPe/ndLHVTH88Rav6N+ffD4/h6IuFMjWCgasFYYsFv0GrvpqREAx3SwmZSvli+0NFXqbxA==}
'@pnpm/exe.linux-arm64@12.8.1':
resolution: {integrity: sha512-q4s9a9X2O3N9aeUFooW24orNrxvu20+jyVUFR5RanPCqOKKPBrgs2iywMkBBx1aXkkzdWT54/mfz8Be8sJlWEw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-ppc64@12.5.1':
resolution: {integrity: sha512-Gg3maDzaE/ZFMV9HIx/BwMN0Y6QbEs13URfxmiYHtKjjLAs5wEQZRMUP87YNLYO7cNaEfbM8GRbS9vPosyD9Gw==}
'@pnpm/exe.linux-ppc64@12.8.1':
resolution: {integrity: sha512-F7XSjKJthwCh/L6abZiMpAfo2Cm61SZIT3e4dfgiIjESndlWaXCnfLKngSgZ/SEMsdmHT6dud3+kWIB3tw0/xQ==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-riscv64@12.5.1':
resolution: {integrity: sha512-6fgWxXYMBMsWQ8DAiRevscX4QZQjwh+FsyCj8ZOk8pMXvqeq84MqBLCmS6KckvnbdqJ+HlSVQ7fs/kd0ldwfhA==}
'@pnpm/exe.linux-riscv64@12.8.1':
resolution: {integrity: sha512-z1ecpIK/ZY08Unk69KWWE9867oaKUytGUjrHnBoGFAAhsK+q+0cfvBH+f5fWobJ7FX97leMlLO+gkJolddM45Q==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-s390x@12.5.1':
resolution: {integrity: sha512-nzMZruRvxDhEfYUhzu+7EmM39+82Dgagc/6hPFPqGqzXNGcIG0anuxbUxfeNtI64SHt91KuuYUmCB/inlM+Pag==}
'@pnpm/exe.linux-s390x@12.8.1':
resolution: {integrity: sha512-KU6tnrBfu4uKXTq6N5qJwSm8FSrs9Wc8b5AUEsHK9bRXwNdsZ1/lRxG1++X29SKRW9OSNuDSjxASv5mAvGo1gA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-x64-musl@12.5.1':
resolution: {integrity: sha512-kHCbegdTNHpzmPtUD4S5fqkVkqgdQR47spF9p2VPP3dIIkZl6Ytk8w0vhlAsAGgge8FmucfwX+vvPKgm0NtOCQ==}
'@pnpm/exe.linux-x64-musl@12.8.1':
resolution: {integrity: sha512-eUE8BWJkDr2tJb/yrk0yVnszlmNqFarVxUlqiZ9BAkct28Nq/5g2H0tvMDmPA7fAQW3STNj+omJPPRVT+4s5sQ==}
cpu: [x64]
os: [linux]
libc: [musl]
'@pnpm/exe.linux-x64@12.5.1':
resolution: {integrity: sha512-3PkUBYo5z4dgtlnTNIFj7QGpcDUAuqXz9WGVigPDCeccEnhGiRkWmA5102TmYJHtwJP3LfmE+ZF9PGeWhn8p9Q==}
'@pnpm/exe.linux-x64@12.8.1':
resolution: {integrity: sha512-8bDZ0lZlCdi2rvnFul7EYgcC7zKeWSe76y8JV2oXobaS8p9i9d6PSf6LgLtTM0fI7R9Oh4eLCbveXyNDMmvZ+g==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@pnpm/exe.win32-arm64@12.5.1':
resolution: {integrity: sha512-49NvjZIXHly56/PLoEDD7VphbO4N8dwMXoApElDFCpVGDNGeKlwlib1tXtnpTF6i2/XIsAj7GgatHB5KHXgBnA==}
'@pnpm/exe.win32-arm64@12.8.1':
resolution: {integrity: sha512-MsT0dlrRxnCRCHCaosNbhWpEiAFnFuMEu3KuDJDU41BXgTwiINxU8goloUSUDejWZUqKaUqNC/qUTihl9nFtqg==}
cpu: [arm64]
os: [win32]
'@pnpm/exe.win32-x64@12.5.1':
resolution: {integrity: sha512-ePUmQFPAPJFNMwg1lelDx2PdjHqYRiF0yfg5e6qeDbPNOu97QNo557Ru/SxmCrmt8ydQWNuZXWpdEp019md5vw==}
'@pnpm/exe.win32-x64@12.8.1':
resolution: {integrity: sha512-SWtPe0PsbTTk//gJND10tMdOfCYjrkq5+qV49hzVhY7xz2iJ339Rc+xwASlcvbwTfrvH39YNqpKYibD+CRGLwA==}
cpu: [x64]
os: [win32]
pnpm@12.5.1:
resolution: {integrity: sha512-4/MFvHhKK8ifWtO2E4iJRw+ujSr182thIW7JHCw9ZAiXdfneOKrDMQROpA8kXLDVZmOS399lgk4ZB+9qLGLeXw==}
pnpm@12.8.1:
resolution: {integrity: sha512-9kupB1B/XOr+BsjTjmBS0BeURFgOwSed3Vv8EctIqoomRLZlmOB+dh2oSHKp/FfV+QK4f6SdAkGY1VhhKqu+RQ==}
engines: {node: '>=18.*'}
hasBin: true
snapshots:
'@pnpm/exe.android-arm64@12.5.1':
'@pnpm/exe.android-arm64@12.8.1':
optional: true
'@pnpm/exe.android-x64@12.5.1':
'@pnpm/exe.android-x64@12.8.1':
optional: true
'@pnpm/exe.darwin-arm64@12.5.1':
'@pnpm/exe.darwin-arm64@12.8.1':
optional: true
'@pnpm/exe.darwin-x64@12.5.1':
'@pnpm/exe.darwin-x64@12.8.1':
optional: true
'@pnpm/exe.freebsd-x64@12.5.1':
'@pnpm/exe.freebsd-x64@12.8.1':
optional: true
'@pnpm/exe.linux-arm64-musl@12.5.1':
'@pnpm/exe.linux-arm64-musl@12.8.1':
optional: true
'@pnpm/exe.linux-arm64@12.5.1':
'@pnpm/exe.linux-arm64@12.8.1':
optional: true
'@pnpm/exe.linux-ppc64@12.5.1':
'@pnpm/exe.linux-ppc64@12.8.1':
optional: true
'@pnpm/exe.linux-riscv64@12.5.1':
'@pnpm/exe.linux-riscv64@12.8.1':
optional: true
'@pnpm/exe.linux-s390x@12.5.1':
'@pnpm/exe.linux-s390x@12.8.1':
optional: true
'@pnpm/exe.linux-x64-musl@12.5.1':
'@pnpm/exe.linux-x64-musl@12.8.1':
optional: true
'@pnpm/exe.linux-x64@12.5.1':
'@pnpm/exe.linux-x64@12.8.1':
optional: true
'@pnpm/exe.win32-arm64@12.5.1':
'@pnpm/exe.win32-arm64@12.8.1':
optional: true
'@pnpm/exe.win32-x64@12.5.1':
'@pnpm/exe.win32-x64@12.8.1':
optional: true
pnpm@12.5.1:
pnpm@12.8.1:
optionalDependencies:
'@pnpm/exe.android-arm64': 12.5.1
'@pnpm/exe.android-x64': 12.5.1
'@pnpm/exe.darwin-arm64': 12.5.1
'@pnpm/exe.darwin-x64': 12.5.1
'@pnpm/exe.freebsd-x64': 12.5.1
'@pnpm/exe.linux-arm64': 12.5.1
'@pnpm/exe.linux-arm64-musl': 12.5.1
'@pnpm/exe.linux-ppc64': 12.5.1
'@pnpm/exe.linux-riscv64': 12.5.1
'@pnpm/exe.linux-s390x': 12.5.1
'@pnpm/exe.linux-x64': 12.5.1
'@pnpm/exe.linux-x64-musl': 12.5.1
'@pnpm/exe.win32-arm64': 12.5.1
'@pnpm/exe.win32-x64': 12.5.1
'@pnpm/exe.android-arm64': 12.8.1
'@pnpm/exe.android-x64': 12.8.1
'@pnpm/exe.darwin-arm64': 12.8.1
'@pnpm/exe.darwin-x64': 12.8.1
'@pnpm/exe.freebsd-x64': 12.8.1
'@pnpm/exe.linux-arm64': 12.8.1
'@pnpm/exe.linux-arm64-musl': 12.8.1
'@pnpm/exe.linux-ppc64': 12.8.1
'@pnpm/exe.linux-riscv64': 12.8.1
'@pnpm/exe.linux-s390x': 12.8.1
'@pnpm/exe.linux-x64': 12.8.1
'@pnpm/exe.linux-x64-musl': 12.8.1
'@pnpm/exe.win32-arm64': 12.8.1
'@pnpm/exe.win32-x64': 12.8.1
---
lockfileVersion: '9.0'
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "clash-verge"
version = "2.5.6"
version = "2.5.7"
description = "clash verge"
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
license = "GPL-3.0-only"
@@ -99,7 +99,7 @@ tracing = { workspace = 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" }
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",
] }
arc-swap = "1.9.2"
+1 -1
View File
@@ -113,7 +113,7 @@ pub async fn continue_with_sidecar() -> CmdResult {
}
#[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()
}
+15 -9
View File
@@ -108,8 +108,7 @@ impl DnsOverrideState {
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ProfileDnsSettings {
pub enabled: bool,
// Force-enable confirmation is valid only for the current app session.
#[serde(skip)]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub confirmation: Option<String>,
}
@@ -195,7 +194,7 @@ mod tests {
}
#[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 confirmed = IVerge {
profile_dns_settings: [(
@@ -208,15 +207,22 @@ mod tests {
.into(),
..IVerge::default()
};
let settings = confirmed.dns_settings_for("one");
assert!(DnsOverrideState::new("one", source.clone(), settings.enabled, settings.confirmation).enabled);
for saved in [
serde_yaml_ng::to_string(&confirmed)?,
"enable_dns_settings: true\ndns_override_confirmation: provider-dns".to_owned(),
let saved = serde_yaml_ng::to_string(&confirmed)?;
let mut restarted: IVerge = serde_yaml_ng::from_str(&saved)?;
let settings = restarted.dns_settings_for("one");
let state = DnsOverrideState::new("one", source.clone(), settings.enabled, settings.confirmation);
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 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.apply_to(&mut restarted));
assert!(!restarted.dns_settings_for("one").enabled);
+1 -1
View File
@@ -678,7 +678,7 @@ impl CoreManager {
SERVICE_MANAGER.withdraw_sidecar_allowance();
self.rollback_failed_start().await;
} 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}")))
}
+1 -1
View File
@@ -28,7 +28,7 @@ pub use env::FakeEnv;
pub use env::{RealEnv, RunStateEnv};
pub use health::{PendingAction, RunState, RunStateView, ServiceHealth};
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 health::StoredService;
+4 -1
View File
@@ -27,6 +27,9 @@ pub enum ServiceVersionCheck {
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.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CurrentServiceProbe {
@@ -47,7 +50,7 @@ pub fn classify_service_version_reply(reply: &ServiceVersionReply) -> ServiceVer
return match &reply.core {
Some(clash_verge_service_ipc::CoreAvailability::Ready) => ServiceVersionCheck::Ready,
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(
"the selected approved core is missing or does not match; reinstall the service to repair it".into(),
+42 -9
View File
@@ -9,8 +9,8 @@ use crate::{
owner_identity::current_owner_credentials,
proxy_control,
runstate::{
OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch, PendingAction, RUN_STATE, ReadyWaitError,
RunState, RunStateEnv, RunStateStore, ServiceHealth,
CORE_REJECTED_PREFIX, OwnerRecoveryReason, OwnerSample, OwnerStep, OwnerWatch, PendingAction, RUN_STATE,
ReadyWaitError, RunState, RunStateEnv, RunStateStore, ServiceHealth,
},
runtime_bundle::{RemoteProviderRef, collect_runtime_bundle, remote_providers_of},
tray::Tray,
@@ -39,18 +39,31 @@ use std::{
static OWNER_MONITOR_GENERATION: AtomicU64 = AtomicU64::new(0);
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_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")]
pub(crate) fn notify_service_fallback() {
PENDING_SERVICE_FALLBACK_NOTICE.store(true, Ordering::Relaxed);
pub(crate) fn notify_service_fallback(reason: &str) {
*PENDING_SERVICE_FALLBACK_NOTICE.lock() = Some(reason.to_owned());
Handle::notice_message("service_core::sidecar_fallback", "");
}
pub(crate) fn take_service_fallback_notice() -> bool {
PENDING_SERVICE_FALLBACK_NOTICE.swap(false, Ordering::Relaxed)
pub(crate) fn take_service_fallback_notice() -> Option<ServiceFallbackNotice> {
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 {
@@ -833,7 +846,10 @@ fn record_service_start_refusal<E: RunStateEnv>(
store: &RunStateStore<E>,
refusal: ServiceStartRefusal,
) -> 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()));
}
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)`.
start_owner_monitor();
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_OWNER_NOTICE.lock().take();
logging!(
@@ -2312,6 +2328,23 @@ mod tests {
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]
fn cached_readiness_is_false_while_a_service_operation_is_running() {
let store = fake_store();
+1 -1
View File
@@ -1,5 +1,5 @@
{
"version": "2.5.6",
"version": "2.5.7",
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"bundle": {
"active": true,
+11 -6
View File
@@ -100,13 +100,18 @@ export const LayoutSidebar = (props: LayoutSidebarProps) => {
const item = navItemMap.get(path)
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 (
<SortableItem
key={item.path}
id={item.path}
index={index}
disabled={!menuUnlocked}
>
<SortableItem key={item.path} id={item.path} index={index}>
{(sortable) => (
<LayoutItem to={item.path} icon={item.icon} sortable={sortable}>
{t(item.label)}
@@ -4,6 +4,7 @@ import {
type RunState,
getCoreStartupError,
takeDnsOverrideNotice,
takeServiceFallbackNotice,
takeServiceRepairNotice,
} from '@/services/cmds'
import { subscribeVergeEvents } from '@/services/events'
@@ -31,13 +32,13 @@ vi.mock('@/services/cmds', () => ({
getCoreStartupError: vi.fn().mockResolvedValue(null),
takeDiscardedKeysNotice: vi.fn().mockResolvedValue(null),
takeDnsOverrideNotice: vi.fn().mockResolvedValue(false),
takeServiceFallbackNotice: vi.fn().mockResolvedValue(false),
takeServiceFallbackNotice: vi.fn().mockResolvedValue(null),
takeServiceRepairNotice: vi.fn().mockResolvedValue(false),
takeServiceOwnerNotice: vi.fn().mockResolvedValue(null),
}))
vi.mock('@/services/service-request', () => ({ requestService: vi.fn() }))
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', () => ({
revalidateQueries: vi.fn(),
@@ -184,3 +185,26 @@ it('offers service reinstallation for a startup path refusal even before listene
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': () => {
void takeServiceFallbackNotice()
.then((pending) => {
if (pending) {
.then((notice) => {
if (notice?.kind === 'coreRejected') {
showNotice.warning(
'settings.feedback.notifications.clashService.permissionFallback',
{ reason: notice.reason },
0,
)
} else if (notice) {
showNotice.warning(
'settings.feedback.notifications.clashService.sidecarFallback',
)
+5 -1
View File
@@ -186,8 +186,12 @@ export async function takeDnsOverrideNotice() {
return invoke<boolean>('take_dns_override_notice')
}
export type ServiceFallbackNotice =
| { kind: 'unavailable' }
| { kind: 'coreRejected'; reason: string }
export async function takeServiceFallbackNotice() {
return invoke<boolean>('take_service_fallback_notice')
return invoke<ServiceFallbackNotice | null>('take_service_fallback_notice')
}
export interface CoreFailure {