Compare commits

...
6 Commits
Author SHA1 Message Date
❤是纱雾酱哟~ f149604eb6 fix(installer): prompt to terminate running instance before uninstall or overwrite (#8519)
* fix(installer): prompt to terminate running instance before uninstall or overwrite

* fix(installer): detect running application instance during installation

* docs(changelog): add changelog entry for windows installer fix

Add release note entry for detecting running instances before reinstalling or overwriting in the Windows installer.

Assisted-by: VSCode Copilot SDK (Gemini 3.8 Flash)
Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

---------

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2026-11-02 17:59:59 +00:00
Tunglies ebd78ae9ff revert(macos): restore Dock hiding when closing the window
This reverts commit 12f842d038.

Restore the Accessory activation policy when closing the main window or
using Cmd+W so the Dock icon disappears again. Keeping the Regular policy
avoided menu bar jitter but caused the Dock visibility regression in #8513.

Hiding the application before switching to Accessory did not reliably
eliminate the jitter. An isolated Tao 0.37.2 checkout with a native muda
menu reproduced it on macOS 27.2 without CVR or WebView. The responsible
layer remains undetermined and needs separate investigation.

The menu bar jitter reported in #8319 can still occur; this revert restores
Dock behavior and does not claim to fix that issue.

Closes #8513
2026-11-03 00:55:35 +08:00
Tunglies 3027e2b87f fix(proxies): restore GLOBAL selection in global mode
Show the GLOBAL group before configured groups so the global exit can be
selected without changing a shared policy group. Use the displayed groups
for delay subscriptions and verify row identity before reusing the list.

Close #8516
2026-11-02 22:25:35 +08:00
github-actions[bot]andgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> a0e57c5962 Dev: v2.5.10 (#8511)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-11-02 10:47:51 +00:00
Tunglies de15283ef6 fix(release): omit comments when archiving changelog 2026-11-02 18:22:34 +08:00
Tunglies 3f39c2ceca fix(release): filter draft lookup before buffering output 2026-11-02 17:36:27 +08:00
12 changed files with 115 additions and 51 deletions
Generated
+1 -1
View File
@@ -1081,7 +1081,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]] [[package]]
name = "clash-verge" name = "clash-verge"
version = "2.5.9" version = "2.5.10"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"anyhow", "anyhow",
+25 -26
View File
@@ -1,46 +1,45 @@
## v2.5.9 <!-- Release-notes skeleton. Entries accumulate in ./Changelog.md as PRs land;
before publishing a release, distill them:
- **Mihomo(Meta) 内核升级至 v1.19.33** - user-visible changes only — no dev tooling, CI fixes, or refactors whose
effect is already covered by another entry
- describe outcomes, not internals: no internal module names, IPC or
protocol details, or implementation mechanics — write what the user
observes, not how the code achieves it
- one line per theme: merge entries that share a root cause
- each entry fits a single readable line (about 60 CJK characters); if it
overflows, it is packing multiple themes or detail that belongs in the
linked issue/PR — split it or drop the detail
- line grammar: open with a verb (修复/新增/优化), with the platform
first (Windows/macOS/Linux) when the change is platform-specific;
merge sub-symptoms as 主题:症状、症状; full-width punctuation,
「」 for UI labels, backticks for config keys and commands
- platform entries sit under their platform heading (bold, emoji
prefixed, ordered Windows/macOS/Linux, combined for pairs like
macOS/Linux) at the end of their section;
scripts-workflow/group_platforms.sh regroups, --check verifies
HTML comments are stripped by the update dialog's sanitizer and hidden on
GitHub, so they never reach users. -->
## v2.5.10
<details> <details>
<summary><strong> 🐞 修复问题 </strong></summary> <summary><strong> 🐞 修复问题 </strong></summary>
- 修复规则扩展包含空列表项时,「编辑规则」界面报错的问题 - 修复全局模式缺少 `GLOBAL` 策略组,无法单独选择全局出口
- 修复 重启应用后定时自动备份不执行的问题
- 修复托盘测速与代理页行为不一致的问题,移除托盘「测试延迟」入口
- 修复通过 URL 导入订阅时,即使导入的订阅并非当前使用的订阅,也会重新加载当前配置
- 修复 首页 网站测速失败后卡片一直显示测试中
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
- 修复 代理 在全局模式下无法展开节点组
- 修复 自定义 CSS 无法修改编辑器字体和字号的问题
- 修复 WebDAV 设置清空后无法保存
**🍎 macOS** **🖥️ Windows**
- macOS:修复 Bigsur 上首页测速和流量图无法显示的问题 - Windows:修复安装程序重新安装或覆盖时未提示退出运行中应用,导致卸载报错或覆盖失败的问题
**🐧 Linux**
- Linux:修复 deb/rpm 安装包错误包含多余的 `frontend-contract` 可执行文件,导致下游重新打包失败的问题
</details> </details>
<details> <details>
<summary><strong> ✨ 新增功能 </strong></summary> <summary><strong> ✨ 新增功能 </strong></summary>
- 新增虚拟网卡设置的「DNS 模式」选项,支持配置 mihomo 系统 DNS 行为
- 新增「IP 信息」自动刷新开关,关闭后仍可手动刷新
- 新增 Muse AI 解锁检测,针对 Muse AI 特有的 Cloudflare 人机验证增加「Risky」状态标记
</details> </details>
<details> <details>
<summary><strong> 🚀 优化改进 </strong></summary> <summary><strong> 🚀 优化改进 </strong></summary>
- 优化「链式代理」:开启前需确认网速影响提示,空面板新增「关闭」按钮
**🖥️ Windows**
- Windows 系统代理默认绕过 `*.local` 域名,访问局域网设备的 `.local` 主机名时不再经过代理
</details> </details>
+48
View File
@@ -1,3 +1,51 @@
## v2.5.9
- **Mihomo(Meta) 内核升级至 v1.19.33**
<details>
<summary><strong> 🐞 修复问题 </strong></summary>
- 修复规则扩展包含空列表项时,「编辑规则」界面报错的问题
- 修复 重启应用后定时自动备份不执行的问题
- 修复托盘测速与代理页行为不一致的问题,移除托盘「测试延迟」入口
- 修复通过 URL 导入订阅时,即使导入的订阅并非当前使用的订阅,也会重新加载当前配置
- 修复 首页 网站测速失败后卡片一直显示测试中
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
- 修复 代理 在全局模式下无法展开节点组
- 修复 自定义 CSS 无法修改编辑器字体和字号的问题
- 修复 WebDAV 设置清空后无法保存
**🍎 macOS**
- macOS:修复 Bigsur 上首页测速和流量图无法显示的问题
**🐧 Linux**
- Linux:修复 deb/rpm 安装包错误包含多余的 `frontend-contract` 可执行文件,导致下游重新打包失败的问题
</details>
<details>
<summary><strong> ✨ 新增功能 </strong></summary>
- 新增虚拟网卡设置的「DNS 模式」选项,支持配置 mihomo 系统 DNS 行为
- 新增「IP 信息」自动刷新开关,关闭后仍可手动刷新
- 新增 Muse AI 解锁检测,针对 Muse AI 特有的 Cloudflare 人机验证增加「Risky」状态标记
</details>
<details>
<summary><strong> 🚀 优化改进 </strong></summary>
- 优化「链式代理」:开启前需确认网速影响提示,空面板新增「关闭」按钮
**🖥️ Windows**
- Windows 系统代理默认绕过 `*.local` 域名,访问局域网设备的 `.local` 主机名时不再经过代理
</details>
## v2.5.8 ## v2.5.8
<details> <details>
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "clash-verge", "name": "clash-verge",
"version": "2.5.9", "version": "2.5.10",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {
"prepare": "husky || true", "prepare": "husky || true",
+4 -1
View File
@@ -41,7 +41,10 @@ fi
tmpfile=$(mktemp) tmpfile=$(mktemp)
{ {
cat "$CHANGELOG" node -e '
const fs = require("node:fs");
process.stdout.write(fs.readFileSync(process.argv[1], "utf8").replace(/<!--[\s\S]*?-->/g, "").trimStart());
' "$CHANGELOG"
echo echo
echo "" echo ""
if [ -f "$HISTORY" ]; then if [ -f "$HISTORY" ]; then
+8 -3
View File
@@ -652,9 +652,14 @@ function validateTag() {
function prepareDraft() { function prepareDraft() {
const tag = env.RELEASE_TAG const tag = env.RELEASE_TAG
verifyTarget() verifyTarget()
const release = list('releases?per_page=100').find( const result = run('gh', [
(release) => release.tag_name === tag, 'api',
) '--paginate',
endpoint('releases?per_page=100'),
'--jq',
`.[] | select(.tag_name == ${JSON.stringify(tag)}) | {id, draft}`,
])
const release = result ? JSON.parse(result) : null
if (release && !release.draft) if (release && !release.draft)
throw new Error('This release is already public.') throw new Error('This release is already public.')
const draft = const draft =
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "clash-verge" name = "clash-verge"
version = "2.5.9" version = "2.5.10"
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"
+8 -3
View File
@@ -21,6 +21,7 @@ ManifestDPIAwareness PerMonitorV2
!include "FileAssociation.nsh" !include "FileAssociation.nsh"
!include "Win\COM.nsh" !include "Win\COM.nsh"
!include "Win\Propkey.nsh" !include "Win\Propkey.nsh"
!include "Win\RestartManager.nsh"
!include "WinVer.nsh" !include "WinVer.nsh"
!include "LogicLib.nsh" !include "LogicLib.nsh"
!include "StrFunc.nsh" !include "StrFunc.nsh"
@@ -332,6 +333,8 @@ Function PageLeaveReinstall
${EndIf} ${EndIf}
reinst_uninstall: reinst_uninstall:
!insertmacro CheckIfAppIsRunning "$INSTDIR\${MAINBINARYNAME}.exe" "${PRODUCTNAME}"
HideWindow HideWindow
ClearErrors ClearErrors
@@ -368,7 +371,10 @@ Function PageLeaveReinstall
MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)" MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)"
Abort Abort
${EndIf} ${EndIf}
Return
reinst_done: reinst_done:
!insertmacro CheckIfAppIsRunning "$INSTDIR\${MAINBINARYNAME}.exe" "${PRODUCTNAME}"
FunctionEnd FunctionEnd
; 5. Choose install directory page ; 5. Choose install directory page
@@ -901,8 +907,7 @@ Section Install
nsExec::Exec 'netsh int tcp res' nsExec::Exec 'netsh int tcp res'
!include "Win\RestartManager.nsh" !insertmacro CheckIfAppIsRunning "$INSTDIR\${MAINBINARYNAME}.exe" "${PRODUCTNAME}"
!insertmacro CheckIfAppIsRunning "${MAINBINARYNAME}.exe" "${PRODUCTNAME}"
!insertmacro CheckAllVergeProcesses !insertmacro CheckAllVergeProcesses
; Ensure startup folders exist ; Ensure startup folders exist
@@ -1101,7 +1106,7 @@ Section Uninstall
!insertmacro NSIS_HOOK_PREUNINSTALL !insertmacro NSIS_HOOK_PREUNINSTALL
!endif !endif
!insertmacro CheckIfAppIsRunning "${MAINBINARYNAME}.exe" "${PRODUCTNAME}" !insertmacro CheckIfAppIsRunning "$INSTDIR\${MAINBINARYNAME}.exe" "${PRODUCTNAME}"
!insertmacro CheckAllVergeProcesses !insertmacro CheckAllVergeProcesses
!insertmacro RemoveVergeService !insertmacro RemoveVergeService
+1
View File
@@ -316,6 +316,7 @@ pub async fn hide() {
{ {
let _ = window.hide(); let _ = window.hide();
} }
handle::Handle::global().set_activation_policy_accessory();
} }
#[cfg(test)] #[cfg(test)]
+3
View File
@@ -289,6 +289,9 @@ pub fn run() -> std::process::ExitCode {
} }
pub fn handle_window_close(api: &tauri::WindowEvent) { pub fn handle_window_close(api: &tauri::WindowEvent) {
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_accessory();
if core::handle::Handle::global().is_exiting() { if core::handle::Handle::global().is_exiting() {
return; return;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"version": "2.5.9", "version": "2.5.10",
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"bundle": { "bundle": {
"active": true, "active": true,
+14 -14
View File
@@ -206,17 +206,20 @@ export const useRenderList = (
verge?.default_latency_timeout, verge?.default_latency_timeout,
]) ])
const renderGroups = useMemo(() => {
if (!proxyView) return []
if (mode === 'rule') return proxyView.groups
const global = proxyView.global ? [proxyView.global] : []
return mode === 'global' ? [...global, ...proxyView.groups] : global
}, [mode, proxyView])
// Every group this list draws, so a test settling in any of them re-sorts that group. // Every group this list draws, so a test settling in any of them re-sorts that group.
const renderedGroupNames = useMemo(() => { const renderedGroupNames = useMemo(() => {
if (!proxyView) return [] if (!proxyView) return []
if (isChainMode) if (isChainMode)
return selectedGroup ? [selectedGroup] : [CHAIN_DELAY_GROUP] return selectedGroup ? [selectedGroup] : [CHAIN_DELAY_GROUP]
return mode === 'rule' || mode === 'global' return renderGroups.map(({ name }) => name)
? proxyView.groups.map(({ name }) => name) }, [isChainMode, proxyView, renderGroups, selectedGroup])
: proxyView.global
? [proxyView.global.name]
: []
}, [isChainMode, mode, proxyView, selectedGroup])
const groupDelays = useGroupsDelays(renderedGroupNames) const groupDelays = useGroupsDelays(renderedGroupNames)
const groupCacheRef = useRef<Map<string, GroupCache>>(new Map()) const groupCacheRef = useRef<Map<string, GroupCache>>(new Map())
@@ -258,13 +261,7 @@ export const useRenderList = (
} }
const useRule = mode === 'rule' || mode === 'global' const useRule = mode === 'rule' || mode === 'global'
const renderGroups = useRule
? proxyView.groups
: proxyView.global === null
? []
: [proxyView.global]
const cache = groupCacheRef.current const cache = groupCacheRef.current
let anyChanged = false
const retList = renderGroups.flatMap((group) => { const retList = renderGroups.flatMap((group) => {
const headState = headStates[group.name] || DEFAULT_STATE const headState = headStates[group.name] || DEFAULT_STATE
@@ -281,7 +278,6 @@ export const useRenderList = (
return cached.items return cached.items
} }
anyChanged = true
const ret: IRenderItem[] = [ const ret: IRenderItem[] = [
{ {
type: 0, type: 0,
@@ -350,7 +346,10 @@ export const useRenderList = (
const filtered = !useRule const filtered = !useRule
? retList.slice(1) ? retList.slice(1)
: retList.filter((item) => !item.group.hidden) : retList.filter((item) => !item.group.hidden)
if (!anyChanged && prevListRef.current.length === filtered.length) { if (
prevListRef.current.length === filtered.length &&
filtered.every((item, index) => item === prevListRef.current[index])
) {
return prevListRef.current return prevListRef.current
} }
prevListRef.current = filtered prevListRef.current = filtered
@@ -364,6 +363,7 @@ export const useRenderList = (
latencyTimeout, latencyTimeout,
mode, mode,
proxyView, proxyView,
renderGroups,
selectedGroup, selectedGroup,
]) ])